﻿using EFFC.Frame.Net.Module.Extend.EWRA.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EFFC.Extends.LinqDLR2SQL;
using EFFC.Frame.Net.Unit.DB;
using EFFC.Frame.Net.Base.Data.Base;
using EFFC.Frame.Net.Module.Extend.EWRA.Attributes.Validation;
using EFFC.Frame.Net.Base.Common;
using EFFC.Frame.Net.Base.Data;
using EFFC.Frame.Net.Module.Business.Datas;
using System.IO;
using XHRPMIS.Common;
using EFFC.Frame.Net.Unit.DB.Parameters;
using System.Text;
using EFFC.Frame.Net.Unit.DB.Datas;
using ICPFrameLib.Business;
using ICPFrameLib.Attributes;
using ICPFrameLib.Common;

namespace XHRPMIS.Business.v1._0
{
   public class MetaData : MyRestLogic
{
    string upload_root_path = MyConfig.GetConfiguration("Upload", "File_Path");
    RefExpress ref_express = new RefExpress();
    [EWRARoute("get", "/metadata/support_datatype")]
    [EWRARouteDesc("获取所有支持的数据类型")]
    [EWRAOutputDesc("返回结果", @"{
result:[{
    data_type:'类别名称',
    desc:'说明',
    is_allow_empty_zero_precision:'是否允许精度为空或0',
    is_allow_empty_zero_scale:'是否允许比例为空或0',
    is_allow_pk:'是否允许栏位为PK',
    is_auto_fix:'当栏位不可为空时，是否系统自动填入数据',
    ui_type:'UI类型',
    category:'分类',
    cal_express:'计算表达式'
}]
}")]
    List<object> GetSupportDataType()
    {
        SetCacheEnable(false);
        var metaup = DB.NewMetaUnitParameter();
        var data = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "a")
                    where t.IsVirsualOnly != 1
                    orderby t.sort_num
                    select t).GetQueryList(metaup);
        return (from t in data
                select new
                {
                    data_type = t.DataType,
                    desc = t.DataTypeDesc,
                    is_allow_empty_zero_precision = BoolStd.IsNotBoolThen(t.IsAllowEmptyOrZero_Precision, true),
                    is_allow_empty_zero_scale = BoolStd.IsNotBoolThen(t.IsAllowEmptyOrZero_Scale, true),
                    is_allow_pk = BoolStd.IsNotBoolThen(t.IsAllowPK),
                    is_auto_fix = BoolStd.IsNotBoolThen(t.IsAutoFix),
                    ui_type = t.UI_TYPE,
                    category = t.DataTypeCategory,
                    cal_express = t.CalExpress
                }).ToList<object>();
    }
    [EWRARoute("get", "/metadata/support_datatype_virsual")]
    [EWRARouteDesc("获取虚拟栏位支持的数据类型")]
    [EWRAOutputDesc("返回结果", @"{
result:[{
    data_type:'类别名称',
    desc:'说明',
    is_allow_empty_zero_precision:'是否允许精度为空或0',
    is_allow_empty_zero_scale:'是否允许比例为空或0',
    is_allow_pk:'是否允许栏位为PK',
    is_auto_fix:'当栏位不可为空时，是否系统自动填入数据',
    is_virsual_only:'虚拟栏位专用',
    ui_type:'UI类型',
    category:'分类',
    cal_express:'计算表达式'
}]
}")]
    List<object> GetSupportDataType4Virsual()
    {
        SetCacheEnable(false);
        var metaup = DB.NewMetaUnitParameter();
        var data = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "a")
                    orderby t.sort_num
                    select t).GetQueryList(metaup);
        return (from t in data
                select new
                {
                    data_type = t.DataType,
                    desc = t.DataTypeDesc,
                    is_allow_empty_zero_precision = BoolStd.IsNotBoolThen(t.IsAllowEmptyOrZero_Precision, true),
                    is_allow_empty_zero_scale = BoolStd.IsNotBoolThen(t.IsAllowEmptyOrZero_Scale, true),
                    is_allow_pk = BoolStd.IsNotBoolThen(t.IsAllowPK),
                    is_auto_fix = BoolStd.IsNotBoolThen(t.IsAutoFix),
                    is_virsual_only = BoolStd.IsNotBoolThen(t.IsVirsualOnly, false),
                    ui_type = t.UI_TYPE,
                    category = t.DataTypeCategory,
                    cal_express = t.CalExpress
                }).ToList<object>();
    }
    [EWRARoute("get", "/metadata/category")]
    [EWRARouteDesc("获取所有元数据类别列表")]
    [EWRAOutputDesc("返回结果", @"{
result:[{
    category_no:'类别编号',
    category_name:'类别名称'
}]
}")]
    List<object> GetCategory()
    {
        SetCacheEnable(false);
        var metaup = DB.NewMetaUnitParameter();
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "a")
                orderby t.CategoryNo
                select new
                {
                    category_no = t.CategoryNo,
                    category_name = t.CategoryName
                };

        return s.GetQueryList(metaup).ToList<object>();
    }
    [ActionAuth("MetaData")]
    [EWRARoute("post", "/metadata/category")]
    [EWRARouteDesc("新增元数据类别")]
    [EWRAEmptyValid("category_name")]
    [EWRAAddInput("category_name", "string", "数据集名称", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
    code:""success-成功，failed-失败"",
    msg:""提示信息"",
    category_no:""成功时候返回的category_no""
    }")]
    object AddCategory()
    {
        var category_name = ComFunc.nvl(PostDataD.category_name);
        var metaup = DB.NewMetaUnitParameter();
        BeginTrans();
        if ((from t in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "a")
             where t.CategoryName == category_name
             select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = $"名称:\"{category_name}\"已存在"
            };
        }
        var category_no = "";
        var no = 3;
        var existlist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "a")
                         select new
                         {
                             category_no = t.CategoryNo,
                             category_name = t.CategoryName
                         }).GetQueryList(metaup).Select(d => ComFunc.nvl(d.GetValue("category_no"))).ToList();
        do
        {
            category_no = string.Format("C{0:000}", no);
            if (!existlist.Contains(category_no)) break;
            no++;
        } while (true);
        DB.QuickInsert(metaup, "EXTEND_METADATA_CATEGORY", new
        {
            CategoryNo = category_no,
            CategoryName = category_name,
            add_id = TokenPayLoad.ID,
            add_name = ComFunc.nvl(TokenPayLoad["username"]),
            add_ip = ClientInfo.IP,
            add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
        });

        CommitTrans();

        return new
        {
            code = "success",
            msg = "操作成功",
            category_no
        };
    }
    [ActionAuth("MetaData")]
    [EWRARoute("patch", "/metadata/category/{no}")]
    [EWRARouteDesc("修改元数据类别")]
    [EWRAEmptyValid("category_name")]
    [EWRAAddInput("category_name", "string", "数据集名称", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
    code:""success-成功，failed-失败"",
    msg:""提示信息""
    }")]
    object UpdateCategory(string no)
    {
        var category_name = ComFunc.nvl(PostDataD.category_name);
        var metaup = DB.NewMetaUnitParameter();
        BeginTrans();
        if (!(from t in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "a")
              where t.CategoryNo == no
              select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = $"资料不存在"
            };
        }
        if ((from t in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "a")
             where t.CategoryNo != no && t.CategoryName == category_name
             select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = $"名称:\"{category_name}\"已存在"
            };
        }
        DB.QuickUpdate(metaup, "EXTEND_METADATA_CATEGORY", new
        {
            CategoryName = category_name,
            last_id = TokenPayLoad.ID,
            last_name = ComFunc.nvl(TokenPayLoad["username"]),
            last_ip = ClientInfo.IP,
            last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
        }, new
        {
            CategoryNo = no,
        });

        CommitTrans();

        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }
    [ActionAuth("MetaData")]
    [EWRARoute("delete", "/metadata/category/{no}")]
    [EWRARouteDesc("删除元数据类别")]
    [EWRAEmptyValid("category_name")]
    [EWRAAddInput("category_name", "string", "数据集名称", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
    code:""success-成功，failed-失败"",
    msg:""提示信息""
    }")]
    object DeleteCategory(string no)
    {
        var category_name = ComFunc.nvl(PostDataD.category_name);
        var metaup = DB.NewMetaUnitParameter();
        BeginTrans();
        if (!(from t in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "a")
              where t.CategoryNo == no
              select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = $"资料不存在"
            };
        }
        if ((from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
             where t.MetaCategoryNo == no
             select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = $"类别:\"{category_name}\"有被使用，请先处理该类别下的元数据，再删除本资料"
            };
        }
        DB.QuickDelete(metaup, "EXTEND_METADATA_CATEGORY", new
        {
            CategoryNo = no,
        });

        CommitTrans();

        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }
    [EWRARoute("get", "/metadata/fix_columns")]
    [EWRARouteDesc("获取所有固定栏位")]
    [EWRAOutputDesc("返回结果", @"{
result:[{
    column_name:'栏位名称',
    column_desc:'栏位描述',
    data_type:'栏位类型',
    precision:'数据精度，int类型，无值时为空',
    scale:'比例标准，int类型，无值时为空',
    reference:'栏位关联表达式',
    default_value:'默认值',
    is_allow_empty:'是否允许为空',
    is_pk:'是否为pk',
    is_show:'是否显示',
    sort_num:'排序号',
    format:'格式化表达式',
    memo:'栏位备注',
    format:'格式化设定',
    ui_type:'UI控件类型'
}]
}")]
    List<object> GetFixColumns()
    {
        SetCacheEnable(false);

        return MetaDataUtilities.FixColumns.ToList<object>();
    }
    [EWRARoute("get", "/metadata/{id}/virsual_columns")]
    [EWRARouteDesc("获取指定元数据的虚拟栏位")]
    [EWRAOutputDesc("返回结果", @"{
result:[{
    column_name:'栏位名称',
    column_desc:'栏位描述',
    data_type:'栏位类型',
    precision:'数据精度，int类型，无值时为空',
    scale:'比例标准，int类型，无值时为空',
    reference:'栏位关联表达式',
    default_value:'默认值',
    is_show:'是否显示',
    sort_num:'排序号',
    format:'格式化表达式',
    memo:'栏位备注',
    ui_type:'UI控件类型'
}]
}")]
    List<object> GetVirsualColumns(string id)
    {
        SetCacheEnable(false);

        var metaup = DB.NewMetaUnitParameter();
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "b").LeftJoin() on t.metauid equals t2.metauid
                join t3 in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "c").LeftJoin() on t.metacategoryno equals t3.CategoryNo
                join t4 in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "d").LeftJoin() on t2.MetaDataType equals t4.DataType
                where t2.IsVirsual == 1 && t.metauid == id
                orderby t.metaname, t2.sortnum
                select new
                {
                    t.metauid,
                    t.metaname,
                    t.metadesc,
                    t.metacategoryno,
                    t.islocked,
                    t.iscreated,
                    main_ref = t.MetaMainUID,
                    main_show_col = t.MetaMainShowColumn,
                    t3.categoryname,
                    t2.MetaColumnName,
                    t2.MetaColumnDesc,
                    t2.MetaDataType,
                    t2.MetaDataPrecision,
                    t2.MetaDataScale,
                    t2.MetaReference,
                    t2.MetaDataDefault,
                    t2.MetaAllowEmpty,
                    t2.MetaIsPK,
                    t2.SortNum,
                    t2.IsShow,
                    t2.Memo,
                    t2.MetaFormat,
                    t4.UI_Type
                };
        return (from t in s.GetQueryList(metaup)
                select new
                {
                    column_name = t.GetValue("MetaColumnName"),
                    column_desc = t.GetValue("MetaColumnDesc"),
                    data_type = t.GetValue("MetaDataType"),
                    precision = t.GetValue("MetaDataPrecision"),
                    scale = t.GetValue("MetaDataScale"),
                    //关联信息表达式要做格式转化
                    reference = ref_express.ParseExpress(ComFunc.nvl(t.GetValue("MetaReference"))).ToJSON(),
                    default_value = t.GetValue("MetaDataDefault"),
                    is_show = BoolStd.IsNotBoolThen(t.GetValue("IsShow")),
                    sort_num = t.GetValue("SortNum"),
                    memo = t.GetValue("Memo"),
                    ui_type = t.GetValue("UI_Type"),
                    format = t.GetValue("MetaFormat")
                }).ToList<object>();
    }
    [ActionAuth("MetaData")]
    [EWRARoute("post", "/metadata/{id}/virsual_columns/edit")]
    [EWRARouteDesc("编辑虚拟栏位")]
    [EWRAAddInput("id", "string", "元数据表UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("columns", "array", @"栏位信息,格式为：
[{
    column_name:'栏位名称,英文字符,必须唯一',
    column_desc:'栏位描述，中文描述',
    data_type:'栏位类型，，来源于接口/metadata/support_datatype',
    precision:'栏位数据精度，int类型',
    scale:'比例标准，int类型，仅numberic类型有效',
    default_value:'默认值或表达式，当前支持的标准表达式为:now()(mysql,sqlite不支持),increament(整数)(oracle,sqlite不支持)',
    reference:'栏位关联的信息，该关联信息只适用于一对一的关联，一对多不适用，格式参考《元数据设计说明.docx》',
    is_show:'是否显示',
    sort_num:'排序编号,界面显示栏位会按照排序序号升序来显示',
    memo:'栏位备注',
    format:'格式化设定',
    cal_express:'计算表达式'
}]", "默认为空", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    public object EditVirsualColumn(string id)
    {
        object columnobj = PostDataD.columns;

        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        if (!(from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
              where t.MetaUID == id
              select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = "元数据表不存在"
            };
        }
        if (!(columnobj is IEnumerable<object>))
        {
            return new
            {
                code = "failed",
                msg = "栏位信息格式不正确"
            };
        }
        var columns = (IEnumerable<object>)columnobj;
        var realcolumns = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                           where t.MetaUID == id && t.IsVirsual == 0
                           select t).GetQueryList(metaup);
        foreach (dynamic c in columns)
        {
            if (columns.Where(p => ((dynamic)p).column_name == c.column_name).Count() > 1)
            {
                return new
                {
                    code = "failed",
                    msg = $"栏位名重复({c.column_name})"
                };
            }
            if (realcolumns.Where(p => p.MetaColumnName == c.column_name).Count() > 1)
            {
                return new
                {
                    code = "failed",
                    msg = $"与实体栏位名重复({c.column_name})"
                };
            }
        }
        var support_data_type_list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "a")
                                      select new
                                      {
                                          data_type = t.DataType,
                                          is_allow_empty_precision = t.IsAllowEmptyOrZero_Precision,
                                          is_allow_pk = t.IsAllowPK
                                      }).GetQueryList(metaup);
        var not_empty_precision = support_data_type_list.Where(w => BoolStd.IsNotBoolThen(w.is_allow_empty_precision, true) == false).Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("data_type"))).ToArray();
        var support_data_type = support_data_type_list.Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("data_type"))).ToArray();
        if (columns.Where((p) =>
        {
            dynamic dobj = p;
            string dt = ComFunc.nvl(dobj.data_type);
            return not_empty_precision.Contains(dt) && IntStd.IsNotIntThen(dobj.precision) == 0;
        }).Count() > 0)
        {
            return new
            {
                code = "failed",
                msg = $"数据类型为{string.Join(",", not_empty_precision)}时数据精度不可为空或0"
            };
        }


        var columns_info = new List<object>();
        foreach (dynamic c in columns)
        {
            if (ComFunc.nvl(c.column_name) == ""
                || !support_data_type.Contains((string)ComFunc.nvl(c.data_type)))
            {
                return new
                {
                    code = "failed",
                    msg = "栏位信息格式不正确"
                };
            }
            columns_info.Add(new
            {
                MetaUID = id,
                MetaColumnName = c.column_name,
                MetaColumnDesc = c.column_desc,
                MetaDataType = c.data_type,
                MetaDataPrecision = IntStd.IsInt(c.precision) ? c.precision : null,
                MetaDataScale = IntStd.IsInt(c.scale) ? c.scale : null,
                MetaDataDefault = c.default_value,
                MetaReference = ref_express.ParseExpress(c.reference).ToJSON(),
                MetaAllowEmpty = 1,
                MetaIsPK = 0,
                SortNum = IntStd.IsNotIntThen(c.sort_num),
                IsShow = BoolStd.IsNotBoolThen(c.is_show, true) ? 1 : 0,
                IsVirsual = 1,
                CalExpress = c.cal_express,
                Memo = c.memo,
                MetaFormat = c.format,
                add_id = TokenPayLoad.ID,
                add_ip = ClientInfo.IP,
                add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                last_id = TokenPayLoad.ID,
                last_ip = ClientInfo.IP,
                last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }
        //删除已存在的虚拟栏位
        DB.QuickDelete(metaup, "EXTEND_METADATA_COLUMNS", new
        {
            MetaUID = id,
            IsVirsual = 1
        });
        foreach (var item in columns_info)
        {
            DB.QuickInsert(metaup, "EXTEND_METADATA_COLUMNS", item);
        }

        CommitTrans();

        MetaDataUtilities.RefreshMetaInfo(metaup);
        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }
    [ActionAuth("MetaData")]
    [EWRARouteDesc("获取所有元数据信息的列表")]
    [EWRAAddInput("inc_fc", "bool", "是否包含固定栏位", "默认false", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAOutputDesc("返回结果", @"{
result:[{
    metauid:'元数据表的uid',
    metaname:'元数据表名',
    metadesc:'元数据表描述',
    category_no:'类别编号',
    category_name:'类别名称',
    is_locked:'是否锁定，bool类型',
    is_created:'是否已创建，bool类型'，
    main_ref:'关联主表UID',
    main_show_col:'关联主表显示栏位',
    columns:[{
        column_name:'栏位名称',
        column_desc:'栏位描述',
        data_type:'数据类型'，
        precision:'数据精度，int类型，无值时为空',
        scale:'比例标准，int类型，无值时为空',
        reference:'引用描述',
        default_value:'默认值',
        is_allow_empty:'是否允许为空',
        is_pk:'是否为主键',
        is_show:'栏位是否显示',
        sort_num:'排序编号,界面显示栏位会按照排序序号升序来显示',
        memo:'栏位备注',
        format:'格式化设定',
        ui_type:'UI控件类型',
        is_logic_unique:'唯一键'
    }]
}]
}")]
    public override List<object> get()
    {
        SetCacheEnable(false);
        var inc_fc = BoolStd.IsNotBoolThen(QueryStringD.inc_fc);
        var metaup = DB.NewMetaUnitParameter();
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "b").LeftJoin() on t.metauid equals t2.metauid
                join t3 in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "c").LeftJoin() on t.metacategoryno equals t3.CategoryNo
                join t4 in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "d").LeftJoin() on t2.MetaDataType equals t4.DataType
                where t2.IsVirsual == 0
                orderby t.metaname, t2.sortnum
                select new
                {
                    t.metauid,
                    t.metaname,
                    t.metadesc,
                    t.metacategoryno,
                    t.islocked,
                    t.iscreated,
                    main_ref = t.MetaMainUID,
                    //2020/09/09添加
                    main_show_col = t.MetaMainShowColumn,
                    t3.categoryname,
                    t2.MetaColumnName,
                    t2.MetaColumnDesc,
                    t2.MetaDataType,
                    t2.MetaDataPrecision,
                    t2.MetaDataScale,
                    t2.MetaReference,
                    t2.MetaDataDefault,
                    t2.MetaAllowEmpty,
                    t2.MetaIsPK,
                    t2.SortNum,
                    t2.IsShow,
                    t2.Memo,
                    t2.MetaFormat,
                    t4.UI_Type,
                    t2.MetaLogicUnique
                };
        var rtn = (from t in s.GetQueryList(metaup)
                   group t by t.GetValue("metauid") into g
                   select new
                   {
                       metauid = g.First().GetValue("metauid"),
                       metaname = g.First().GetValue("metaname"),
                       metadesc = g.First().GetValue("metadesc"),
                       category_no = g.First().GetValue("metacategoryno"),
                       category_name = ComFunc.nvl(g.First().GetValue("categoryname")) == "" ? "其他数据集" : g.First().GetValue("categoryname"),
                       is_locked = BoolStd.IsNotBoolThen(g.First().GetValue("islocked")),
                       is_created = BoolStd.IsNotBoolThen(g.First().GetValue("iscreated")),
                       main_ref = g.First().GetValue("main_ref"),
                       //2020/09/09添加
                       main_show_col = g.First().GetValue("main_show_col"),
                       columns = (from tt in g
                                  where ComFunc.nvl(tt.MetaColumnName) != ""
                                  select FrameDLRObject.CreateInstance(new
                                  {
                                      column_name = tt.GetValue("MetaColumnName"),
                                      column_desc = tt.GetValue("MetaColumnDesc"),
                                      data_type = tt.GetValue("MetaDataType"),
                                      precision = tt.GetValue("MetaDataPrecision"),
                                      scale = tt.GetValue("MetaDataScale"),
                                      //关联信息表达式要做格式转化
                                      reference = ref_express.ParseExpress(ComFunc.nvl(tt.GetValue("MetaReference"))).ToJSON(),
                                      default_value = tt.GetValue("MetaDataDefault"),
                                      is_allow_empty = BoolStd.IsNotBoolThen(tt.GetValue("MetaAllowEmpty")),
                                      is_pk = BoolStd.IsNotBoolThen(tt.GetValue("MetaIsPK")),
                                      is_show = BoolStd.IsNotBoolThen(tt.GetValue("IsShow")),
                                      sort_num = tt.GetValue("SortNum"),
                                      memo = tt.GetValue("Memo"),
                                      ui_type = tt.GetValue("UI_Type"),
                                      format = tt.GetValue("MetaFormat"),
                                      is_logic_unique = BoolStd.IsNotBoolThen(tt.GetValue("MetaLogicUnique"))
                                  })).ToList()
                   }).ToList();
        if (inc_fc)
        {
            foreach (var item in rtn)
            {
                item.columns.AddRange(MetaDataUtilities.FixColumns.Select(d =>
                {
                    d.SetValue("default_value", "");
                    return d;
                }));
            }
        }
        return rtn.ToList<object>();

    }
    [ActionAuth("MetaData")]
    [EWRARoute("get", "/metadata/{id}")]
    [EWRARouteDesc("获取单个元数据信息的列表")]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
data:{
    metauid:'元数据表的uid',
    metaname:'元数据表名',
    metadesc:'元数据表描述',
    category_no:'类别编号',
    category_name:'类别名称',
    is_locked:'是否锁定，bool类型',
    is_created:'是否已创建，bool类型'，
    main_ref:'关联主表UID',
    main_show_col:'关联主表显示栏位',
    columns:[{
        column_name:'栏位名称',
        column_desc:'栏位描述',
        data_type:'数据类型'，
        precision:'数据精度，int类型，无值时为空',
        scale:'比例标准，int类型，无值时为空',
        reference:'引用描述',
        default_value:'默认值',
        is_allow_empty:'是否允许为空',
        is_pk:'是否为主键',
        is_show:'栏位是否显示',
        sort_num:'排序编号,界面显示栏位会按照排序序号升序来显示',
        memo:'栏位备注',
        format:'格式化设定',
        ui_type:'UI控件类型',
        is_logic_unique:'唯一键'
    }]
}
}")]
    public object Get(string id)
    {
        var metaup = DB.NewMetaUnitParameter();
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "b").LeftJoin() on t.metauid equals t2.metauid
                join t3 in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "c").LeftJoin() on t.metacategoryno equals t3.CategoryNo
                join t4 in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "d").LeftJoin() on t2.MetaDataType equals t4.DataType
                where t.MetaUID == id && t2.IsVirsual == 0
                select new
                {
                    t.metauid,
                    t.metaname,
                    t.metadesc,
                    t.metacategoryno,
                    t.islocked,
                    t.iscreated,
                    main_ref = t.MetaMainUID,
                    //2020/09/09添加
                    main_show_col = t.MetaMainShowColumn,
                    t3.categoryname,
                    t2.MetaColumnName,
                    t2.MetaColumnDesc,
                    t2.MetaDataType,
                    t2.MetaDataPrecision,
                    t2.MetaDataScale,
                    t2.MetaReference,
                    t2.MetaDataDefault,
                    t2.MetaAllowEmpty,
                    t2.MetaIsPK,
                    t2.SortNum,
                    t2.IsShow,
                    t2.Memo,
                    t2.MetaFormat,
                    t4.UI_Type,
                    t2.MetaLogicUnique
                };
        var list = (from t in s.GetQueryList(metaup)
                    group t by t.GetValue("metauid") into g
                    select new
                    {
                        metauid = g.First().GetValue("metauid"),
                        metaname = g.First().GetValue("metaname"),
                        metadesc = g.First().GetValue("metadesc"),
                        category_no = g.First().GetValue("metacategoryno"),
                        category_name = ComFunc.nvl(g.First().GetValue("categoryname")) == "" ? "其他数据集" : g.First().GetValue("categoryname"),
                        is_locked = BoolStd.IsNotBoolThen(g.First().GetValue("islocked")),
                        is_created = BoolStd.IsNotBoolThen(g.First().GetValue("iscreated")),
                        main_ref = g.First().GetValue("main_ref"),
                        //2020/09/09添加
                        main_show_col = g.First().GetValue("main_show_col"),
                        columns = from tt in g
                                  where ComFunc.nvl(tt.MetaColumnName) != ""
                                  select new
                                  {
                                      column_name = tt.GetValue("MetaColumnName"),
                                      column_desc = tt.GetValue("MetaColumnDesc"),
                                      data_type = tt.GetValue("MetaDataType"),
                                      precision = tt.GetValue("MetaDataPrecision"),
                                      scale = tt.GetValue("MetaDataScale"),
                                      //关联信息表达式要做格式转化
                                      reference = ref_express.ParseExpress(ComFunc.nvl(tt.GetValue("MetaReference"))).ToJSON(),
                                      default_value = tt.GetValue("MetaDataDefault"),
                                      is_allow_empty = BoolStd.IsNotBoolThen(tt.GetValue("MetaAllowEmpty")),
                                      is_pk = BoolStd.IsNotBoolThen(tt.GetValue("MetaIsPK")),
                                      is_show = BoolStd.IsNotBoolThen(tt.GetValue("IsShow")),
                                      sort_num = tt.GetValue("SortNum"),
                                      memo = tt.GetValue("Memo"),
                                      ui_type = tt.GetValue("UI_Type"),
                                      is_logic_unique = BoolStd.IsNotBoolThen(tt.GetValue("MetaLogicUnique"))
                                  }
                    }).ToList<object>();
        if (list.Count <= 0)
        {
            return new
            {
                code = "failed",
                msg = "元数据表不存在"
            };
        }
        return new
        {
            code = "success",
            msg = "",
            data = list.First()
        };
    }
    [ActionAuth("MetaData")]
    [EWRAEmptyValid("name,columns")]
    [EWRARouteDesc("新增一个元数据表")]
    [EWRAAddInput("name", "string", "元数据表名", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("desc", "string", "元数据表描述", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("category_no", "string", "元数据表的类别编号", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("main_ref", "string", "关联主表UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("main_show_col", "string", "关联主表显示栏位", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("columns", "array", @"栏位信息,格式为：
[{
    column_name:'栏位名称,英文字符,必须唯一',
    column_desc:'栏位描述，中文描述',
    data_type:'栏位类型，，来源于接口/metadata/support_datatype',
    precision:'栏位数据精度，int类型',
    scale:'比例标准，int类型，仅numberic类型有效',
    default_value:'默认值或表达式，当前支持的标准表达式为:now()(mysql,sqlite不支持),increament(整数)(oracle,sqlite不支持)',
    reference:'栏位关联的信息，该关联信息只适用于一对一的关联，一对多不适用，格式参考《元数据设计说明.docx》',
    is_allow_empty:'是否允许为空，为bool类型',
    is_pk:'是否为PK，为bool类型',
    is_show:'是否显示',
    sort_num:'排序编号,界面显示栏位会按照排序序号升序来显示',
    memo:'栏位备注',
    format:'格式化设定',
    is_logic_unique:'是否唯一键'
}]", "默认为空", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
metauid:""成功时候返回的UID""
}")]
    public override object post()
    {
        var metaname = ComFunc.nvl(PostDataD.name);
        var metadesc = ComFunc.nvl(PostDataD.desc);
        object columnobj = PostDataD.columns;
        var metauid = Guid.NewGuid().ToString();
        var categoryno = ComFunc.nvl(PostDataD.category_no);
        var main_ref = ComFunc.nvl(PostDataD.main_ref);
        var main_show_col = ComFunc.nvl(PostDataD.main_show_col);

        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        if ((from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
             where t.MetaName == metaname
             select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = "表名已存在"
            };
        }
        if (!(columnobj is IEnumerable<object>))
        {
            return new
            {
                code = "failed",
                msg = "栏位信息格式不正确"
            };
        }
        var columns = (IEnumerable<object>)columnobj;

        foreach (dynamic c in columns)
        {
            if (columns.Where(p => ((dynamic)p).column_name == c.column_name).Count() > 1)
            {
                return new
                {
                    code = "failed",
                    msg = $"栏位名重复({c.column_name})"
                };
            }
        }
        var support_data_type_list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "a")
                                      select new
                                      {
                                          data_type = t.DataType,
                                          is_allow_empty_precision = t.IsAllowEmptyOrZero_Precision,
                                          is_allow_pk = t.IsAllowPK
                                      }).GetQueryList(metaup);
        var not_empty_precision = support_data_type_list.Where(w => BoolStd.IsNotBoolThen(w.is_allow_empty_precision, true) == false).Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("data_type"))).ToArray();
        var support_data_type = support_data_type_list.Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("data_type"))).ToArray();
        if (columns.Where((p) =>
        {
            dynamic dobj = p;
            string dt = ComFunc.nvl(dobj.data_type);
            return not_empty_precision.Contains(dt) && IntStd.IsNotIntThen(dobj.precision) == 0;
        }).Count() > 0)
        {
            return new
            {
                code = "failed",
                msg = $"数据类型为{string.Join(",", not_empty_precision)}时数据精度不可为空或0"
            };
        }
        //检核栏位不可为PK的情况
        var not_allow_pk_datatype = support_data_type_list.Where(w => !BoolStd.IsNotBoolThen(w.is_allow_pk, false)).Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("data_type"))).ToArray();

        var columns_info = new List<object>();
        foreach (dynamic c in columns)
        {
            if (ComFunc.nvl(c.column_name) == ""
                || !support_data_type.Contains((string)ComFunc.nvl(c.data_type)))
            {
                return new
                {
                    code = "failed",
                    msg = "栏位信息格式不正确"
                };
            }
            if (BoolStd.IsNotBoolThen(c.is_pk, false) && not_allow_pk_datatype.Contains((string)ComFunc.nvl(c.data_type)))
            {
                return new
                {
                    code = "failed",
                    msg = $"数据类型为{string.Join(",", not_allow_pk_datatype)}时不可为PK"
                };
            }
            columns_info.Add(new
            {
                MetaUID = metauid,
                MetaColumnName = c.column_name,
                MetaColumnDesc = c.column_desc,
                MetaDataType = c.data_type,
                MetaDataPrecision = IntStd.IsInt(c.precision) ? c.precision : null,
                MetaDataScale = IntStd.IsInt(c.scale) ? c.scale : null,
                MetaDataDefault = c.default_value,
                MetaReference = ref_express.ParseExpress(c.reference).ToJSON(),
                MetaAllowEmpty = BoolStd.IsNotBoolThen(c.is_allow_empty, false) ? 1 : 0,
                MetaIsPK = BoolStd.IsNotBoolThen(c.is_pk, false) ? 1 : 0,
                SortNum = IntStd.IsNotIntThen(c.sort_num),
                IsShow = BoolStd.IsNotBoolThen(c.is_show, true) ? 1 : 0,
                MetaLogicUnique = BoolStd.IsNotBoolThen(c.is_logic_unique, false) ? 1 : 0,
                IsVirsual = 0,
                Memo = c.memo,
                MetaFormat = c.format,
                add_id = TokenPayLoad.ID,
                add_ip = ClientInfo.IP,
                add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                last_id = TokenPayLoad.ID,
                last_ip = ClientInfo.IP,
                last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }

        DB.QuickInsert(metaup, "EXTEND_METADATA", new
        {
            MetaUID = metauid,
            MetaName = metaname,
            MetaDesc = metadesc,
            MetaCategoryNo = categoryno,
            IsCreated = 0,
            IsLocked = 0,
            MetaMainUID = main_ref,
            MetaMainShowColumn = main_show_col,
            add_id = TokenPayLoad.ID,
            add_ip = ClientInfo.IP,
            add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
            last_id = TokenPayLoad.ID,
            last_ip = ClientInfo.IP,
            last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
        });
        foreach (var item in columns_info)
        {
            DB.QuickInsert(metaup, "EXTEND_METADATA_COLUMNS", item);
        }

        CommitTrans();
        MetaDataUtilities.RefreshMetaInfo(metaup);
        return new
        {
            code = "success",
            msg = "操作成功",
            metauid = metauid
        };
    }
    [ActionAuth("MetaData")]
    [EWRARouteDesc("删除一个元数据表,如果table已经创建，则table也会drop掉（如果table中有比较多的数据会比较耗时）")]
    [EWRAAddInput("id", "string", "元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAOutputDesc("返回结果", @"根据http的状态码来识别，204标识操作成功，404表示操作识别未找到删除的资料")]
    public override bool delete(string id)
    {
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        var msg = "";
        if (DoDeleteMeta(metaup, up, id, ref msg))
        {
            CommitTrans();
            MetaDataUtilities.RefreshMetaInfo(metaup);
            return true;
        }
        else
        {
            RollBack();
            return false;
        }


    }
    [ActionAuth("MetaData")]
    [EWRAEmptyValid("name,columns")]
    [EWRARouteDesc("修改一个元数据表的信息，如果元数据表已经创建或则不能做修改动作")]
    [EWRAAddInput("id", "string", "元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("name", "string", "元数据表名", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("desc", "string", "元数据表描述", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("category_no", "string", "元数据表的类别编号", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("main_ref", "string", "关联主表UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("main_show_col", "string", "关联主表显示栏位", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("columns", "array", @"栏位信息,格式为：
[{
    column_name:'栏位名称,英文字符',
    column_desc:'栏位描述，中文描述',
    data_type:'栏位类型，来源于接口/metadata/support_datatype',
    precision:'栏位数据精度，int类型',
    scale:'比例标准，int类型，仅numberic类型有效',
    default_value:'默认值或表达式，当前支持的标准表达式为:now()(mysql,sqlite不支持),increament(整数)(oracle,sqlite不支持)',
    reference:'栏位关联的信息，该关联信息只适用于一对一的关联，一对多不适用，格式参考《元数据设计说明.docx》',
    is_allow_empty:'是否允许为空，为bool类型',
    is_pk:'是否为PK，为bool类型',
    is_show:'是否显示',
    sort_num:'排序编号,界面显示栏位会按照排序序号升序来显示',
    memo:'栏位备注',
    format:'格式化设定',
    is_logic_unique:'是否唯一键'
}]", "默认为空", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
metauid:""成功时候返回的UID""
}")]
    public override object patch(string id)
    {
        var metaname = ComFunc.nvl(PostDataD.name);
        var metadesc = ComFunc.nvl(PostDataD.desc);
        object columnobj = PostDataD.columns;
        var categoryno = ComFunc.nvl(PostDataD.category_no);
        var main_ref = ComFunc.nvl(PostDataD.main_ref);
        var main_show_col = ComFunc.nvl(PostDataD.main_show_col);

        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                where t.metauid == id
                select t;
        var list = s.GetQueryList(metaup);
        if (!s.IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = "元数据表不存在"
            };
        }
        dynamic info = list.First();
        bool iscreated = BoolStd.IsNotBoolThen(info.iscreated, false);
        if (iscreated)
        {
            return new
            {
                code = "failed",
                msg = "元数据表已经创建，不可修改"
            };
        }

        if ((from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
             where t.MetaName == metaname && t.metauid != id
             select t).IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = "表名已存在"
            };
        }
        if (!(columnobj is IEnumerable<object>))
        {
            return new
            {
                code = "failed",
                msg = "栏位信息格式不正确"
            };
        }
        var columns = (IEnumerable<object>)columnobj;
        var support_data_type_list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "a")
                                      select new
                                      {
                                          data_type = t.DataType,
                                          is_allow_empty_precision = t.IsAllowEmptyOrZero_Precision
                                      }).GetQueryList(metaup);
        var not_empty_precision = support_data_type_list.Where(w => BoolStd.IsNotBoolThen(w.is_allow_empty_precision, true) == false).Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("data_type"))).ToArray();
        var support_data_type = support_data_type_list.Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("data_type"))).ToArray();
        if (columns.Where((p) =>
        {
            dynamic dobj = p;
            string dt = ComFunc.nvl(dobj.data_type);
            return not_empty_precision.Contains(dt) && IntStd.IsNotIntThen(dobj.precision) == 0;
        }).Count() > 0)
        {
            return new
            {
                code = "failed",
                msg = $"数据类型为{string.Join(",", not_empty_precision)}时数据精度不可为空或0"
            };
        }

        var columns_info = new List<object>();
        foreach (dynamic c in columns)
        {
            if (ComFunc.nvl(c.column_name) == ""
                || !support_data_type.Contains((string)ComFunc.nvl(c.data_type)))
            {
                return new
                {
                    code = "failed",
                    msg = "栏位信息格式不正确"
                };
            }
            columns_info.Add(new
            {
                MetaUID = id,
                MetaColumnName = c.column_name,
                MetaColumnDesc = c.column_desc,
                MetaDataType = c.data_type,
                MetaDataPrecision = IntStd.IsInt(c.precision) ? c.precision : null,
                MetaDataScale = IntStd.IsInt(c.scale) ? c.scale : null,
                MetaDataDefault = c.default_value,
                MetaReference = ref_express.ParseExpress(c.reference).ToJSON(),
                MetaAllowEmpty = BoolStd.IsNotBoolThen(c.is_allow_empty, false) ? 1 : 0,
                MetaLogicUnique = BoolStd.IsNotBoolThen(c.is_logic_unique, false) ? 1 : 0,
                MetaIsPK = BoolStd.IsNotBoolThen(c.is_pk, false) ? 1 : 0,
                IsShow = BoolStd.IsNotBoolThen(c.is_show, true) ? 1 : 0,
                IsVirsual = 0,
                SortNum = IntStd.IsNotIntThen(c.sort_num),
                Memo = c.memo,
                MetaFormat = c.format,
                add_id = TokenPayLoad.ID,
                add_ip = ClientInfo.IP,
                add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                last_id = TokenPayLoad.ID,
                last_ip = ClientInfo.IP,
                last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }

        DB.QuickUpdate(metaup, "EXTEND_METADATA", new
        {
            MetaName = metaname,
            MetaDesc = metadesc,
            MetaCategoryNo = categoryno,
            MetaMainUID = main_ref,
            MetaMainShowColumn = main_show_col,
            last_id = TokenPayLoad.ID,
            last_ip = ClientInfo.IP,
            last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
        }, new
        {
            MetaUID = id,
        });
        DB.QuickDelete(metaup, "EXTEND_METADATA_COLUMNS", new
        {
            MetaUID = id
        });
        foreach (var item in columns_info)
        {
            DB.QuickInsert(metaup, "EXTEND_METADATA_COLUMNS", item);
        }

        CommitTrans();
        MetaDataUtilities.RefreshMetaInfo(metaup);
        return new
        {
            code = "success",
            msg = "操作成功",
            metauid = id
        };
    }
    [ActionAuth("MetaData")]
    [EWRAEmptyValid("columns")]
    [EWRARoute("patch", "/metadata/{id}/alter")]
    [EWRARouteDesc("修改一个已创建的元数据表的信息")]
    [EWRAAddInput("id", "string", "元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("desc", "string", "元数据表描述", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("category_no", "string", "元数据表的类别编号", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("main_ref", "string", "关联主表UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("main_show_col", "string", "关联主表显示栏位", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("columns", "array", @"栏位信息,格式为：
[{
    column_name:'栏位名称,英文字符',
    column_desc:'栏位描述，中文描述',
    reference:'栏位关联的信息',
    is_show:'是否显示',
    is_logic_unique:'是否唯一键',
    sort_num:'排序编号,界面显示栏位会按照排序序号升序来显示',
    memo:'栏位备注',
    format:'格式化设定'
}]", "默认为空", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
metauid:""成功时候返回的UID""
}")]
    object Alter(string id)
    {
        var metadesc = ComFunc.nvl(PostDataD.desc);
        object columnobj = PostDataD.columns;
        var categoryno = ComFunc.nvl(PostDataD.category_no);
        var main_ref = ComFunc.nvl(PostDataD.main_ref);
        var main_show_col = ComFunc.nvl(PostDataD.main_show_col);

        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                where t.metauid == id
                select t;
        var list = s.GetQueryList(metaup);
        if (!s.IsExists(metaup))
        {
            return new
            {
                code = "failed",
                msg = "元数据表不存在"
            };
        }
        dynamic info = list.First();
        bool iscreated = BoolStd.IsNotBoolThen(info.iscreated, false);
        bool islocked = BoolStd.IsNotBoolThen(info.islocked, false);
        if (islocked)
        {
            return new
            {
                code = "failed",
                msg = "元数据表已经锁定，不可修改"
            };
        }

        if (!(columnobj is IEnumerable<object>))
        {
            return new
            {
                code = "failed",
                msg = "栏位信息格式不正确"
            };
        }
        var columns = (IEnumerable<object>)columnobj;

        var columns_info = new List<object>();
        foreach (dynamic c in columns)
        {
            DB.QuickUpdate(metaup, "EXTEND_METADATA_COLUMNS", new
            {
                MetaColumnDesc = c.column_desc,
                MetaReference = ref_express.ParseExpress(c.reference).ToJSON(),
                IsShow = BoolStd.IsNotBoolThen(c.is_show, true) ? 1 : 0,
                MetaLogicUnique = BoolStd.IsNotBoolThen(c.is_logic_unique, false) ? 1 : 0,
                SortNum = IntStd.IsNotIntThen(c.sort_num),
                Memo = c.memo,
                MetaFormat = c.format,
                last_id = TokenPayLoad.ID,
                last_ip = ClientInfo.IP,
                last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
            }, new
            {
                MetaUID = id,
                MetaColumnName = c.column_name
            });
        }

        DB.QuickUpdate(metaup, "EXTEND_METADATA", new
        {
            MetaDesc = metadesc,
            MetaCategoryNo = categoryno,
            MetaMainUID = main_ref,
            MetaMainShowColumn = main_show_col,
            last_id = TokenPayLoad.ID,
            last_ip = ClientInfo.IP,
            last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
        }, new
        {
            MetaUID = id,
        });

        CommitTrans();
        MetaDataUtilities.RefreshMetaInfo(metaup);
        return new
        {
            code = "success",
            msg = "操作成功",
            metauid = id
        };
    }
    [ActionAuth("MetaData")]
    [EWRARoute("patch", "/metadata/{id}/lock")]
    [EWRARouteDesc("锁定一个元数据表，使其不可用被删除")]
    [EWRAAddInput("id", "string", "元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    object Lock(string id)
    {
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();


        var msg = "";
        if (DoLock(metaup, id, ref msg))
        {
            CommitTrans();
            MetaDataUtilities.RefreshMetaInfo(metaup);
            return new
            {
                code = "success",
                msg = "操作成功"
            };
        }
        else
        {
            RollBack();
            return new
            {
                code = "failed",
                msg
            };
        }
    }
    [ActionAuth("MetaData")]
    [EWRARoute("patch", "/metadata/{id}/unlock")]
    [EWRARouteDesc("解锁一个元数据表，使其可被删除")]
    [EWRAAddInput("id", "string", "元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    object UnLock(string id)
    {
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();

        var msg = "";
        if (DoUnlock(metaup, id, ref msg))
        {
            CommitTrans();
            MetaDataUtilities.RefreshMetaInfo(metaup);
            return new
            {
                code = "success",
                msg = "操作成功"
            };
        }
        else
        {
            RollBack();
            return new
            {
                code = "failed",
                msg
            };
        }
    }
    [EWRAEmptyValid("id")]
    [ActionAuth("MetaData")]
    [EWRARoute("patch", "/metadata/create")]
    [EWRARouteDesc("创建一个元数据表，并自动锁定（元数据表未锁定时才能操作）")]
    [EWRAAddInput("id", "string", "元数据表的UID,多个用逗号分隔", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    object CreateTable()
    {
        string ids = ComFunc.nvl(PostDataD.id);
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        var msg = "";
        if (DoCreateTable(metaup, up, ids, ref msg))
        {
            CommitTrans();
            MetaDataUtilities.RefreshMetaInfo(metaup);
            return new
            {
                code = "success",
                msg = "操作成功"
            };
        }
        else
        {
            RollBack();
            return new
            {
                code = "failed",
                msg
            };
        }
    }

    [ActionAuth("MetaData")]
    [EWRAEmptyValid("id")]
    [EWRARoute("patch", "/metadata/{id}/drop")]
    [EWRARouteDesc("Drop一个元数据表，元数据表未锁定时才能操作")]
    [EWRAAddInput("id", "string", "元数据表的UID,多个用逗号分隔", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    object DropTable(string id)
    {
        string ids = ComFunc.nvl(PostDataD.id);
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        var msg = "";
        if (DoDropTable(metaup, up, ids, ref msg))
        {
            CommitTrans();
            MetaDataUtilities.RefreshMetaInfo(metaup);
            return new
            {
                code = "success",
                msg = "操作成功"
            };
        }
        else
        {
            RollBack();
            return new
            {
                code = "failed",
                msg
            };
        }
    }
    [ActionAuth("MetaData")]
    [EWRAEmptyValid("to_table")]
    [EWRARoute("post", "/metadata/{id}/copytable")]
    [EWRARouteDesc("Copy一个元数据表并创建目标表，元数据表创建后并且未锁定时才能操作")]
    [EWRAAddInput("id", "string", "元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("to_table", "string", "目标表名", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("with_data", "bool", "是否同时copy数据", "默认值为false", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
meta_uid:'生成的新的元数据表的uid'
}")]
    object CopyTable(string id)
    {
        string to_table = ComFunc.nvl(PostDataD.to_table);
        bool with_data = BoolStd.IsNotBoolThen(PostDataD.with_data);
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        var msg = "";
        var to_uid = "";
        if (DoCopyTable(metaup, up, id, to_table, with_data, ref msg, ref to_uid))
        {
            CommitTrans();
            MetaDataUtilities.RefreshMetaInfo(metaup);
            return new
            {
                code = "success",
                msg = "操作成功",
                meta_uid = id
            };
        }
        else
        {
            RollBack();
            return new
            {
                code = "failed",
                msg
            };
        }


    }
    [ActionAuth("MetaData")]
    [EWRAEmptyValid("to_id")]
    [EWRARoute("patch", "/metadata/{id}/copydata")]
    [EWRARouteDesc("Copy一个元数据表数据到另一个元数据表，元数据表和目标元数据表创建后才能操作")]
    [EWRAAddInput("id", "string", "元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("to_id", "string", "目标元数据表的UID", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("if_not_exists", "bool", "是否判断是否存在，注意：该过滤条件不是根据每笔资料进行比对的，而是根据目标表是否存在数据来作为判定依据，因此会出现只要目标表存在资料，无论与来源数据是否相同都不会执行写入操作", "默认值为false", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("columns", "string", @"json结构，先采用urlcode，再采用base64加密，json格式如下：{
    from_column1:'to_column1',//from_column1为来源表的栏位，to_column1为目标表的栏位
    ......
    from_columnN:'to_columnN'
}", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("where", "string", @"array结构，先采用urlcode，再采用base64加密，array格式如下：[{
    column:'来源栏位名称',
    op:'操作符,like-模糊查询，=-精确查询，>-大于,>=-大于等于，<-小于，<=-小于等于',
    value:'值'
}]", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    object CopyData(string id)
    {
        string to_id = ComFunc.nvl(PostDataD.to_id);
        bool if_not_exists = BoolStd.IsNotBoolThen(PostDataD.if_not_exists);
        FrameDLRObject columns = FrameDLRObject.IsJsonThen(ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.columns)));
        object[] where = FrameDLRObject.IsJsonArrayThen(ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.where)));
        BeginTrans();
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        var msg = "";
        if (DoCopyData(metaup, up, id, to_id, columns, where, if_not_exists, ref msg))
        {
            CommitTrans();
            return new
            {
                code = "success",
                msg = "操作成功"
            };
        }
        else
        {
            RollBack();
            return new
            {
                code = "failed",
                msg
            };
        }


    }
    [EWRARoute("get", "/metadata/alltableschema")]
    [EWRARouteDesc("获取所有元数据和词典表的规格信息")]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
data:[{
    uid:'元数据表的uid',
    name:'元数据表名',
    desc:'元数据表描述',
    category_no:'类别编号',
    category_name:'类别名称',
    main_ref:'关联主表UID',
    main_show_col:'关联主表显示栏位',
    columns:[{
        column_name:'栏位名称',
        column_desc:'栏位描述',
        data_type:'数据类型'，
        precision:'数据精度，int类型，无值时为空',
        scale:'比例标准，int类型，无值时为空',
        reference:'引用描述',
        default_value:'默认值',
        is_allow_empty:'是否允许为空',
        is_pk:'是否为主键',
        is_show:'栏位是否显示',
        sort_num:'排序编号,界面显示栏位会按照排序序号升序来显示',
        column_memo:'栏位备注',
        format:'格式化设定',
        ui_type:'UI控件类型',
        is_logic_unique:'是否唯一键'
    }]
}]
}")]
    object GetTableSchema()
    {
        var metaup = DB.NewMetaUnitParameter();
        SetCacheEnable(false);
        var rtn = new List<object>();
        var list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                    join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "b") on t.metauid equals t2.metauid
                    join t3 in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "c").LeftJoin() on t.metacategoryno equals t3.categoryno
                    join t4 in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "d").LeftJoin() on t2.MetaDataType equals t4.DataType
                    where t2.IsVirsual == 0
                    orderby t.metaname, t2.sortnum, t2.metacolumnname ascending
                    select new
                    {
                        uid = t.metauid,
                        name = t.metaname,
                        desc = t.metadesc,
                        main_ref = t.MetaMainUID,
                        main_show_col = t.MetaMainShowColumn,
                        category_no = t3.categoryno,
                        category_name = t3.categoryname,
                        column_name = t2.metacolumnname,
                        column_desc = t2.metacolumndesc,
                        column_memo = t2.memo,
                        data_type = t2.MetaDataType,
                        precision = t2.MetaDataPrecision,
                        scale = t2.MetaDataScale,
                        reference = t2.MetaReference,
                        default_value = t2.MetaDataDefault,
                        is_allow_empty = t2.MetaAllowEmpty,
                        is_pk = t2.MetaIsPK,
                        sort_num = t2.SortNum,
                        is_show = t2.IsShow,
                        memo = t2.Memo,
                        format = t2.MetaFormat,
                        ui_type = t4.UI_Type,
                        is_logic_unique = t2.MetaLogicUnique
                    }).GetQueryList(metaup);
        var metagrouplist = (from t in list
                             group t by new
                             {
                                 uid = t.GetValue("uid"),
                                 name = t.GetValue("name"),
                                 desc = t.GetValue("desc"),
                                 category_no = t.GetValue("category_no"),
                                 category_name = t.GetValue("category_name")
                             } into g
                             select new
                             {
                                 uid = g.First().GetValue("uid"),
                                 name = g.First().GetValue("name"),
                                 desc = g.First().GetValue("desc"),
                                 main_ref = g.First().GetValue("main_ref"),
                                 main_show_col = g.First().GetValue("main_show_col"),
                                 category_no = g.First().GetValue("category_no"),
                                 category_name = g.First().GetValue("category_name"),
                                 columns = (from gg in g
                                            select new
                                            {
                                                column_name = gg.GetValue("column_name"),
                                                column_desc = gg.GetValue("column_desc"),
                                                column_memo = gg.GetValue("column_memo"),
                                                format = gg.GetValue("format"),
                                                ui_type = gg.GetValue("ui_type"),
                                                precision = gg.GetValue("MetaDataPrecision"),
                                                scale = gg.GetValue("MetaDataScale"),
                                                //关联信息表达式要做格式转化
                                                reference = ref_express.ParseExpress(ComFunc.nvl(gg.GetValue("reference"))).ToJSON(),
                                                default_value = gg.GetValue("default_value"),
                                                is_allow_empty = BoolStd.IsNotBoolThen(gg.GetValue("is_allow_empty")),
                                                is_pk = BoolStd.IsNotBoolThen(gg.GetValue("is_pk")),
                                                is_show = BoolStd.IsNotBoolThen(gg.GetValue("is_show")),
                                                sort_num = gg.GetValue("sort_num"),
                                                memo = gg.GetValue("memo"),
                                                is_logic_unique = BoolStd.IsNotBoolThen(gg.GetValue("is_logic_unique"))
                                            }).ToList()
                             }).ToList();
        foreach (var item in metagrouplist)
        {
            foreach (var c in MetaDataUtilities.FixColumns)
            {
                var name = ComFunc.nvl(c.GetValue("column_name"));
                if (name.StartsWith("add_")
                    || name.StartsWith("last_"))
                {
                    continue;
                }
                item.columns.Add(new
                {
                    column_name = (object)name,
                    column_desc = c.GetValue("column_desc"),
                    column_memo = (object)"",
                    format = c.GetValue("format"),
                    ui_type = c.GetValue("ui_type"),
                    precision = c.GetValue("MetaDataPrecision"),
                    scale = c.GetValue("MetaDataScale"),
                    //关联信息表达式要做格式转化
                    reference = ref_express.ParseExpress(ComFunc.nvl(c.GetValue("reference"))).ToJSON(),
                    default_value = c.GetValue("default_value"),
                    is_allow_empty = BoolStd.IsNotBoolThen(c.GetValue("is_allow_empty")),
                    is_pk = BoolStd.IsNotBoolThen(c.GetValue("is_pk")),
                    is_show = BoolStd.IsNotBoolThen(c.GetValue("is_show")),
                    sort_num = c.GetValue("sort_num"),
                    memo = c.GetValue("memo"),
                    is_logic_unique = BoolStd.IsNotBoolThen(c.GetValue("is_logic_unique"))
                });
            }
        }
        rtn.AddRange(metagrouplist);

        var diclist = (from t in DB.LamdaTable(metaup, "EXTEND_DICTIONARY_TABLE", "a")
                       orderby t.dic_name
                       select new
                       {
                           uid = t.dic_uid,
                           name = t.dic_name,
                           desc = t.dic_desc,
                           category_no = "DIC",
                           category_name = "词典表",
                           is_tree = t.istree,
                           main_ref = "",
                           main_show_col = "",
                       }).GetQueryList(metaup);
        var diccolumns = new dynamic[] { new {column_name = "code",column_desc="编号",only_tree = false, precision=50, is_pk = true, is_allow_empty = false},
                                            new{ column_name = "value",column_desc="值",only_tree = false, precision=100, is_pk = false, is_allow_empty = true},
                                            new{ column_name = "level",column_desc="层级",only_tree = true, precision=0, is_pk = false, is_allow_empty = true},
                                            new{ column_name = "p_code",column_desc="父编号",only_tree = true, precision=50, is_pk = false, is_allow_empty = true}
            };
        var dicgrouplist = from t in diclist
                           select new
                           {
                               t.uid,
                               t.name,
                               t.desc,
                               t.category_no,
                               t.category_name,
                               t.main_ref,
                               t.main_show_col,
                               columns = BoolStd.IsNotBoolThen(t.is_tree, false) ? from gg in diccolumns
                                                                                   select new
                                                                                   {
                                                                                       gg.column_name,
                                                                                       gg.column_desc,
                                                                                       column_memo = "",
                                                                                       format = (object)"",
                                                                                       ui_type = (object)"",
                                                                                       precision = gg.precision,
                                                                                       scale = (object)0,
                                                                                       //关联信息表达式要做格式转化
                                                                                       reference = "",
                                                                                       default_value = "",
                                                                                       gg.is_allow_empty,
                                                                                       gg.is_pk,
                                                                                       is_show = true,
                                                                                       sort_num = 0,
                                                                                       memo = "",
                                                                                       is_logic_unique = false
                                                                                   } : from gg in diccolumns
                                                                                       where gg.only_tree == false
                                                                                       select new
                                                                                       {
                                                                                           gg.column_name,
                                                                                           gg.column_desc,
                                                                                           column_memo = "",
                                                                                           format = (object)"",
                                                                                           ui_type = (object)"",
                                                                                           precision = gg.precision,
                                                                                           scale = (object)0,
                                                                                           //关联信息表达式要做格式转化
                                                                                           reference = "",
                                                                                           default_value = "",
                                                                                           gg.is_allow_empty,
                                                                                           gg.is_pk,
                                                                                           is_show = true,
                                                                                           sort_num = 0,
                                                                                           memo = "",
                                                                                           is_logic_unique = false
                                                                                       }
                           };
        rtn.AddRange(dicgrouplist);
        return new
        {
            code = "success",
            msg = "",
            data = rtn
        };
    }
    [EWRARoute("get", "/metadata/alltableschema/cadecase_ms")]
    [EWRARouteDesc("获取主从级联表的规格信息")]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
data:[{
    uid:'元数据表的uid',
    name:'元数据表名',
    desc:'元数据表描述',
    category_no:'类别编号',
    category_name:'类别名称',
    main_ref:'关联主表UID',
    main_show_col:'关联主表显示栏位',
    columns:[{
        column_name:'栏位名称',
        column_desc:'栏位描述',
        column_memo:'栏位备注',
        ui_type:'UI控件类型',
        format:'格式化设定'
    }]
}]
}")]
    object GetCadecaseMSTableSchema()
    {
        var metaup = DB.NewMetaUnitParameter();
        SetCacheEnable(false);
        var rtn = new List<object>();
        var list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                    join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "b") on t.metauid equals t2.metauid
                    join t3 in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "c").LeftJoin() on t.metacategoryno equals t3.categoryno
                    join t4 in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "d").LeftJoin() on t2.MetaDataType equals t4.DataType
                    where t2.IsVirsual == 0
                    orderby t.metaname, t2.sortnum, t2.metacolumnname ascending
                    select new
                    {
                        uid = t.metauid,
                        name = t.metaname,
                        desc = t.metadesc,
                        main_ref = t.MetaMainUID,
                        main_show_col = t.MetaMainShowColumn,
                        category_no = t3.categoryno,
                        category_name = t3.categoryname,
                        column_name = t2.metacolumnname,
                        column_desc = t2.metacolumndesc,
                        column_memo = t2.memo,
                        format = t2.MetaFormat,
                        ui_type = t4.UI_Type
                    }).GetQueryList(metaup);
        var metagrouplist = (from t in list
                             where ComFunc.nvl(t.main_ref) != ""
                             group t by new
                             {
                                 uid = t.GetValue("uid"),
                                 name = t.GetValue("name"),
                                 desc = t.GetValue("desc"),
                                 category_no = t.GetValue("category_no"),
                                 category_name = t.GetValue("category_name")
                             } into g
                             select new
                             {
                                 uid = g.First().GetValue("uid"),
                                 name = g.First().GetValue("name"),
                                 desc = g.First().GetValue("desc"),
                                 main_ref = g.First().GetValue("main_ref"),
                                 main_show_col = g.First().GetValue("main_show_col"),
                                 category_no = g.First().GetValue("category_no"),
                                 category_name = g.First().GetValue("category_name"),
                                 columns = (from gg in g
                                            select new
                                            {
                                                column_name = gg.GetValue("column_name"),
                                                column_desc = gg.GetValue("column_desc"),
                                                column_memo = gg.GetValue("column_memo"),
                                                format = gg.GetValue("format"),
                                                ui_type = gg.GetValue("ui_type")
                                            }).ToList()
                             }).ToList();
        foreach (var item in metagrouplist)
        {
            foreach (var c in MetaDataUtilities.FixColumns)
            {
                var name = ComFunc.nvl(c.GetValue("column_name"));
                if (name.StartsWith("add_")
                    || name.StartsWith("last_"))
                {
                    continue;
                }
                item.columns.Add(new
                {
                    column_name = (object)name,
                    column_desc = c.GetValue("column_desc"),
                    column_memo = (object)"",
                    format = c.GetValue("column_desc"),
                    ui_type = c.GetValue("ui_type")
                });
            }
        }
        rtn.AddRange(metagrouplist);
        return new
        {
            code = "success",
            msg = "",
            data = rtn
        };
    }
    [EWRARoute("get", "/metadata/alltableschema/cadecase_tree")]
    [EWRARouteDesc("获取树结构表的规格信息")]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
data:[{
    uid:'元数据表的uid',
    name:'元数据表名',
    desc:'元数据表描述',
    category_no:'类别编号',
    category_name:'类别名称',
    main_ref:'关联主表UID',
    main_show_col:'关联主表显示栏位',
    columns:[{
        column_name:'栏位名称',
        column_desc:'栏位描述',
        column_memo:'栏位备注',
        ui_type:'UI控件类型',
        format:'格式化设定'
    }]
}]
}")]
    object GetCadecaseTreeTableSchema()
    {
        var metaup = DB.NewMetaUnitParameter();
        SetCacheEnable(false);
        var rtn = new List<object>();
        var list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                    join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "b") on t.metauid equals t2.metauid
                    join t3 in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "c").LeftJoin() on t.metacategoryno equals t3.categoryno
                    join t4 in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "d").LeftJoin() on t2.MetaDataType equals t4.DataType
                    where t2.IsVirsual == 0
                    orderby t.metaname, t2.sortnum, t2.metacolumnname ascending
                    select new
                    {
                        uid = t.metauid,
                        name = t.metaname,
                        desc = t.metadesc,
                        main_ref = t.MetaMainUID,
                        main_show_col = t.MetaMainShowColumn,
                        category_no = t3.categoryno,
                        category_name = t3.categoryname,
                        column_name = t2.metacolumnname,
                        column_desc = t2.metacolumndesc,
                        column_memo = t2.memo,
                        format = t2.MetaFormat,
                        ui_type = t4.UI_Type
                    }).GetQueryList(metaup);
        var metagrouplist = (from t in list
                             group t by new
                             {
                                 uid = t.GetValue("uid"),
                                 name = t.GetValue("name"),
                                 desc = t.GetValue("desc"),
                                 category_no = t.GetValue("category_no"),
                                 category_name = t.GetValue("category_name")
                             } into g
                             select new
                             {
                                 uid = g.First().GetValue("uid"),
                                 name = g.First().GetValue("name"),
                                 desc = g.First().GetValue("desc"),
                                 main_ref = g.First().GetValue("main_ref"),
                                 main_show_col = g.First().GetValue("main_show_col"),
                                 category_no = g.First().GetValue("category_no"),
                                 category_name = g.First().GetValue("category_name"),
                                 columns = (from gg in g
                                            select new
                                            {
                                                column_name = gg.GetValue("column_name"),
                                                column_desc = gg.GetValue("column_desc"),
                                                column_memo = gg.GetValue("column_memo"),
                                                format = gg.GetValue("format"),
                                                ui_type = gg.GetValue("ui_type")
                                            }).ToList()
                             }).ToList();
        foreach (var item in metagrouplist)
        {
            foreach (var c in MetaDataUtilities.FixColumns)
            {
                var name = ComFunc.nvl(c.GetValue("column_name"));
                if (name.StartsWith("add_")
                    || name.StartsWith("last_"))
                {
                    continue;
                }
                item.columns.Add(new
                {
                    column_name = (object)name,
                    column_desc = c.GetValue("column_desc"),
                    column_memo = (object)"",
                    format = c.GetValue("column_desc"),
                    ui_type = c.GetValue("ui_type")
                });
            }
        }
        rtn.AddRange(metagrouplist);

        var diclist = (from t in DB.LamdaTable(metaup, "EXTEND_DICTIONARY_TABLE", "a")
                       orderby t.dic_name
                       select new
                       {
                           uid = t.dic_uid,
                           name = t.dic_name,
                           desc = t.dic_desc,
                           category_no = "DIC",
                           category_name = "词典表",
                           is_tree = t.istree,
                           main_ref = "",
                           main_show_col = "",
                       }).GetQueryList(metaup);
        var diccolumns = new dynamic[] { new {column_name = "code",column_desc="编号",only_tree = false},
                                            new{ column_name = "value",column_desc="值",only_tree = false},
                                            new{ column_name = "level",column_desc="层级",only_tree = true},
                                            new{ column_name = "p_code",column_desc="父编号",only_tree = true}
            };
        var dicgrouplist = from t in diclist
                           where BoolStd.IsNotBoolThen(t.is_tree)
                           select new
                           {
                               t.uid,
                               t.name,
                               t.desc,
                               t.category_no,
                               t.category_name,
                               t.main_ref,
                               t.main_show_col,
                               columns = BoolStd.IsNotBoolThen(t.is_tree, false) ? from gg in diccolumns
                                                                                   select new
                                                                                   {
                                                                                       gg.column_name,
                                                                                       gg.column_desc,
                                                                                       column_memo = "",
                                                                                       format = (object)"",
                                                                                       ui_type = (object)""
                                                                                   } : from gg in diccolumns
                                                                                       where gg.only_tree == false
                                                                                       select new
                                                                                       {
                                                                                           gg.column_name,
                                                                                           gg.column_desc,
                                                                                           column_memo = "",
                                                                                           format = (object)"",
                                                                                           ui_type = (object)""
                                                                                       }
                           };
        rtn.AddRange(dicgrouplist);
        return new
        {
            code = "success",
            msg = "",
            data = rtn
        };
    }
    [EWRAAuth(true)]
    [EWRARoute("ws", "/metadata/genscripts")]
    [EWRARouteDesc("将指定的元数据生成脚本并下载")]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    object GenScripts()
    {
        var metaup = DB.NewMetaUnitParameter();
        var metalist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                        select new
                        {
                            t.MetaUID,
                            t.MetaName,
                            t.MetaDesc
                        }).GetQueryList(metaup);
        var metaoptions = from t in metalist
                          select new
                          {
                              code = t.MetaUID,
                              value = $"{t.MetaDesc}({t.MetaName})"
                          };
        var dicmata = metaoptions.ToDictionary(k => ComFunc.nvl(k.GetValue("code")), v => ComFunc.nvl(v.GetValue("value")));
        var uids = WS.SendMultiSelectMsgAndRead("请选择元数据:", metaoptions, 5 * 60);
        if (string.IsNullOrEmpty(uids)) return new
        {
            code = "failed",
            msg = "未选择任何元数据，操作终止"
        };

        var msg = "";
        var arr = uids.Split(",");
        var list = new List<object>();
        WS.SendProgressBarMsg($"进行生成操作，总计{arr.Length}个元数据", 0, 0, arr.Length);
        var index = 0;
        foreach (var id in arr)
        {
            dynamic result = null;
            if (!GenScriptBy(metaup, id, ref msg, ref result))
            {
                var confirm_result = WS.SendConfirmMsgAndRead($"操作失败({msg}),是否继续?", 2 * 60);
                var iscontinue = BoolStd.IsNotBoolThen(confirm_result);
                if (!iscontinue) return new
                {
                    code = "failed",
                    msg = "用户终止操作"
                };
            }
            list.Add(result);
            index++;
            WS.SendProgressBarMsg($"元数据{dicmata[id]}生成成功", index, 0, arr.Length);
        }
        var dobj = FrameDLRObject.CreateInstance(EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);

        var content = ComFunc.ToJson(list, false);
        dobj.Content = content;
        var sign_str = ComFunc.getMD5_String(((FrameDLRObject)dobj).ToJSONString(true));
        dobj.ValidSign = sign_str;
        if (WS.SendFile("meta_script.json", Encoding.UTF8.GetBytes(((FrameDLRObject)dobj).ToJSONString(true))))
        {
            return new
            {
                code = "success",
                msg = "操作成功"
            };
        }
        else
        {
            return new
            {
                code = "failed",
                msg = "操作失败"
            };
        }
    }
    [EWRAAuth(true)]
    [EWRARoute("patch", "/metadata/export_scripts")]
    [EWRARouteDesc("将指定的元数据生成脚本并下载")]
    [EWRAAddInput("ids", "string", "元数据表的UID,多个用逗号分隔", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
filetype:'文件类型',
filename:'文件名称',
filelength:'文件长度',
file:'文件内容，采用base64加密'
}")]
    object GenScriptsByIDs()
    {
        string ids = ComFunc.nvl(PostDataD.ids);
        var metaup = DB.NewMetaUnitParameter();
        var data = new List<object>();
        var arr = ids.Split(",", StringSplitOptions.RemoveEmptyEntries);
        var msg = "";
        foreach (var id in arr)
        {
            dynamic obj = null;
            if (!GenScriptBy(metaup, id, ref msg, ref obj))
            {
                return new
                {
                    code = "failed",
                    msg
                };
            }
            data.Add(obj);
        }
        var dobj = FrameDLRObject.CreateInstance(EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);

        var content = ComFunc.ToJson(data, false);
        dobj.Content = content;
        var sign_str = ComFunc.getMD5_String(((FrameDLRObject)dobj).ToJSONString(true));
        dobj.ValidSign = sign_str;

        return FileHelper.DoDownLoad("meta_script.json", Encoding.UTF8.GetBytes(((FrameDLRObject)dobj).ToJSONString(true)));
    }
    [EWRAAuth(true)]
    [EWRARoute("patch", "/metadata/import_scripts")]
    [EWRARouteDesc("导入脚本")]
    [EWRAAddInput("data", "json", @"导入的文件，格式如下：{
filetype:'文件类型',
filename:'文件名称',
filelength:'文件长度',
file:'文件内容，采用base64加密'
}", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息""
}")]
    object ImportScripts()
    {
        dynamic data = FrameDLRObject.IsJsonThen(PostDataD.data);
        if (data == null) return new
        {
            code = "failed",
            msg = "上传格式不正确"
        };
        var file = ComFunc.nvl(data.file);
        if (string.IsNullOrEmpty(file)) return new
        {
            code = "failed",
            msg = "上传文件无效，终止操作"
        };
        var content = ComFunc.IsBase64Then(file);
        if (content == "") return new
        {
            code = "failed",
            msg = "上传文件格式无效，终止操作"
        };
        FrameDLRObject dobj = FrameDLRObject.IsJsonThen(content, null, EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);
        if (dobj == null) return new
        {
            code = "failed",
            msg = "上传文件格式无效，终止操作"
        };
        var valid_sign = ComFunc.nvl(dobj.GetValue("ValidSign"));
        if (valid_sign == null) return new
        {
            code = "failed",
            msg = "上传文件不合法，终止操作"
        };
        dobj.Remove("ValidSign");
        var sign_str = ComFunc.getMD5_String(dobj.ToJSONString(true));
        if (sign_str != valid_sign) return new
        {
            code = "failed",
            msg = "上传文件校验失败，终止操作"
        };
        var scripts = FrameDLRObject.IsJsonArrayThen(ComFunc.nvl(dobj.GetValue("Content")));
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        BeginTrans();
        var index = 0;
        foreach (dynamic s in scripts)
        {
            index++;

            var metauid = s.MetaInfo.MetaUID;
            var msg = "";
            var metalist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                            where t.MetaUID == metauid
                            select t).GetQueryList(metaup);
            var metacolumnlist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                                  where t.MetaUID == metauid
                                  select t).GetQueryList(metaup);

            var bak_name = $"Bak_{DateTime.Now.ToString("MMddHHmmssfff")}";
            var to_uid = "";
            if (metalist.Count > 0)
            {
                //解锁表
                if (!DoUnlock(metaup, metauid, ref msg))
                {
                    RollBack();
                    return new
                    {
                        code = "failed",
                        msg = $"{s.MetaInfo.MetaDesc}解锁失败:{msg}"
                    };
                }
                //备份表
                if (!DoCopyTable(metaup, up, metauid, bak_name, true, ref msg, ref to_uid))
                {
                    RollBack();
                    return new
                    {
                        code = "failed",
                        msg = $"{s.MetaInfo.MetaDesc}备份失败:{msg}"
                    };
                }
                //删除元数据资料
                if (!DoDeleteMeta(metaup, up, metauid, ref msg))
                {
                    RollBack();
                    return new
                    {
                        code = "failed",
                        msg = $"{s.MetaInfo.MetaDesc}删除失败:{msg}"
                    };
                }
            }
            //写入新的meta信息
            s.MetaInfo.IsCreated = 0;
            s.MetaInfo.IsLocked = 0;
            DB.QuickInsert(metaup, "EXTEND_METADATA", s.MetaInfo, true);
            foreach (var c in s.MetaColumn)
            {
                if (ComFunc.nvl(c.MetaDataPrecision) == "")
                {
                    c.MetaDataPrecision = null;
                }
                if (ComFunc.nvl(c.MetaDataScale) == "")
                {
                    c.MetaDataScale = null;
                }
                c.MetaLogicUnique = BoolStd.ConvertTo(c.MetaLogicUnique, 1, 0);
                c.IsShow = BoolStd.ConvertTo(c.IsShow, 1, 0);
                c.IsVirsual = BoolStd.ConvertTo(c.IsVirsual, 1, 0);
                c.add_time = DateTimeStd.IsDateTime(c.add_time) ? DateTimeStd.IsDateTimeThen(c.add_time, "yyyy-MM-dd HH:mm:ss") : DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                c.last_time = DateTimeStd.IsDateTime(c.last_time) ? DateTimeStd.IsDateTimeThen(c.last_time, "yyyy-MM-dd HH:mm:ss") : DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                DB.QuickInsert(metaup, "EXTEND_METADATA_COLUMNS", c, true);
            }
            //创建table
            if (!DoCreateTable(metaup, up, metauid, ref msg))
            {
                RollBack();
                return new
                {
                    code = "failed",
                    msg
                };
            }
            if (metalist.Count > 0)
            {
                dynamic metainfo = metalist.First();
                var newmetacolumns = ((IEnumerable<object>)s.MetaColumn).Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("MetaColumnName"))).ToList();
                //恢复数据
                FrameDLRObject copycolumne = FrameDLRObject.CreateInstance(EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);
                foreach (var item in metacolumnlist)
                {
                    if (BoolStd.IsNotBoolThen(item.GetValue("IsVirsual"))) continue;
                    var column = ComFunc.nvl(item.GetValue("MetaColumnName"));
                    if (newmetacolumns.Contains(column))
                    {
                        copycolumne.SetValue(column, column);
                    }
                }
                if (!DoCopyData(metaup, up, to_uid, metauid, copycolumne, null, true, ref msg))
                {
                    RollBack();
                    return new
                    {
                        code = "failed",
                        msg = $"{s.MetaInfo.MetaDesc}恢复数据失败:{msg}"
                    };
                }
                //删除备份表
                if (!DoUnlock(metaup, to_uid, ref msg))
                {
                    RollBack();
                    return new
                    {
                        code = "failed",
                        msg = $"{s.MetaInfo.MetaDesc}解锁备份数据失败:{msg}"
                    };
                }
                if (!DoDeleteMeta(metaup, up, to_uid, ref msg))
                {
                    RollBack();
                    return new
                    {
                        code = "failed",
                        msg = $"{s.MetaInfo.MetaDesc}删除备份表失败:{msg}"
                    };
                }
            }
            //锁定
            DoLock(metaup, metauid, ref msg);
        }
        CommitTrans();
        MetaDataUtilities.RefreshMetaInfo(metaup);
        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }
    [EWRAAuth(true)]
    [EWRARoute("ws", "/metadata/importscripts")]
    [EWRARouteDesc("导入脚本并执行")]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
data:
}")]
    object ImportScript()
    {
        var result = WS.SendUploadFileMsgAndRead($"请上传脚本文件:", 5 * 60);
        if (string.IsNullOrEmpty(result)) return new
        {
            code = "failed",
            msg = "上传文件无效，终止操作"
        };
        var fileobj = FrameDLRObject.IsJsonThen(result);
        if (fileobj == null) return new
        {
            code = "failed",
            msg = "上传文件格式无效，终止操作"
        };
        var content = ComFunc.IsBase64Then(ComFunc.nvl(fileobj.GetValue("file")));
        if (content == "") return new
        {
            code = "failed",
            msg = "上传文件格式无效，终止操作"
        };
        var dobj = FrameDLRObject.IsJsonThen(content, null, EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);
        if (dobj == null) return new
        {
            code = "failed",
            msg = "上传文件格式无效，终止操作"
        };
        var valid_sign = ComFunc.nvl(dobj.GetValue("ValidSign"));
        if (valid_sign == null) return new
        {
            code = "failed",
            msg = "上传文件不合法，终止操作"
        };
        dobj.Remove("ValidSign");
        var sign_str = ComFunc.getMD5_String(dobj.ToJSONString(true));
        if (sign_str != valid_sign) return new
        {
            code = "failed",
            msg = "上传文件校验失败，终止操作"
        };
        var scripts = FrameDLRObject.IsJsonArrayThen(ComFunc.nvl(dobj.GetValue("Content")));
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        WS.SendProgressBarMsg($"进行生成操作，共计{scripts.Count()}元数据脚本", 0, 0, scripts.Count());
        var index = 0;
        foreach (dynamic s in scripts)
        {
            index++;
            if (WS.IsClose())
            {
                return new
                {
                    code = "failed",
                    msg = "连接中断"
                };
            }

            var metauid = s.MetaInfo.MetaUID;
            var msg = "";
            var metalist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                            where t.MetaUID == metauid
                            select t).GetQueryList(metaup);
            var metacolumnlist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                                  where t.MetaUID == metauid
                                  select t).GetQueryList(metaup);

            var bak_name = $"Bak_{DateTime.Now.ToString("MMddHHmmssfff")}";
            var to_uid = "";
            if (metalist.Count > 0)
            {
                //解锁表
                if (!DoUnlock(metaup, metauid, ref msg))
                {
                    WS.SendConsoleMsg($"{s.MetaInfo.MetaDesc}解锁失败:{msg}");
                }
                //备份表
                if (!DoCopyTable(metaup, up, metauid, bak_name, true, ref msg, ref to_uid))
                {
                    WS.SendConsoleMsg($"{s.MetaInfo.MetaDesc}备份失败:{msg}");
                }
                //删除元数据资料
                if (!DoDeleteMeta(metaup, up, metauid, ref msg))
                {
                    WS.SendConsoleMsg($"{s.MetaInfo.MetaDesc}删除失败:{msg}");
                }
            }
            //写入新的meta信息
            s.MetaInfo.IsCreated = 0;
            s.MetaInfo.IsLocked = 0;
            DB.QuickInsert(metaup, "EXTEND_METADATA", s.MetaInfo, true);
            foreach (var c in s.MetaColumn)
            {
                if (ComFunc.nvl(c.MetaDataPrecision) == "")
                {
                    c.MetaDataPrecision = null;
                }
                if (ComFunc.nvl(c.MetaDataScale) == "")
                {
                    c.MetaDataScale = null;
                }
                c.MetaLogicUnique = BoolStd.ConvertTo(c.MetaLogicUnique, 1, 0);
                c.IsShow = BoolStd.ConvertTo(c.IsShow, 1, 0);
                c.IsVirsual = BoolStd.ConvertTo(c.IsVirsual, 1, 0);
                c.add_time = DateTimeStd.IsDateTime(c.add_time) ? DateTimeStd.IsDateTimeThen(c.add_time, "yyyy-MM-dd HH:mm:ss") : DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                c.last_time = DateTimeStd.IsDateTime(c.last_time) ? DateTimeStd.IsDateTimeThen(c.last_time, "yyyy-MM-dd HH:mm:ss") : DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                DB.QuickInsert(metaup, "EXTEND_METADATA_COLUMNS", c, true);
            }
            //创建table
            if (!DoCreateTable(metaup, up, metauid, ref msg))
            {
                WS.SendConsoleMsg($"创建元数据表{s.MetaInfo.MetaDesc}失败:{msg}");
                var r = WS.SendConfirmMsgAndRead($"当前{s.MetaInfo.MetaDesc}的创建操作失败({msg}),是否继续?", 2 * 60);
                var iscontinue = BoolStd.IsNotBoolThen(r);
                if (!iscontinue)
                {
                    return new
                    {
                        code = "failed",
                        msg = "用户终止操作"
                    };
                }
                else
                {
                    WS.SendProgressBarMsg($"当前完成{s.MetaInfo.MetaDesc}的操作", index, 0, scripts.Count());
                    continue;
                }
            }
            if (metalist.Count > 0)
            {
                dynamic metainfo = metalist.First();
                var newmetacolumns = ((IEnumerable<object>)s.MetaColumn).Select(d => ComFunc.nvl(((FrameDLRObject)d).GetValue("MetaColumnName"))).ToList();
                //恢复数据
                FrameDLRObject copycolumne = FrameDLRObject.CreateInstance(EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);
                foreach (var item in metacolumnlist)
                {
                    var column = ComFunc.nvl(item.GetValue("MetaColumnName"));
                    if (newmetacolumns.Contains(column))
                    {
                        copycolumne.SetValue(column, column);
                    }
                }
                if (!DoCopyData(metaup, up, to_uid, metauid, copycolumne, null, true, ref msg))
                {
                    WS.SendConsoleMsg($"{s.MetaInfo.MetaDesc}恢复数据失败:{msg}");
                }
                //删除备份表
                if (!DoUnlock(metaup, to_uid, ref msg))
                {
                    WS.SendConsoleMsg($"{s.MetaInfo.MetaDesc}删除备份表失败:{msg}");
                }
                if (!DoDeleteMeta(metaup, up, to_uid, ref msg))
                {
                    WS.SendConsoleMsg($"{s.MetaInfo.MetaDesc}删除备份表失败:{msg}");
                }
            }
            //锁定
            DoLock(metaup, metauid, ref msg);

            WS.SendProgressBarMsg($"当前完成{s.MetaInfo.MetaDesc}的操作", index, 0, scripts.Count());
        }
        MetaDataUtilities.RefreshMetaInfo(metaup);
        return new
        {
            code = "success",
            msg = "操作成功"
        };
    }

    [EWRAAuth(true)]
    [EWRARoute("patch", "/metadata/doc/create")]
    [EWRARouteDesc("在知识库上创建元数据文档")]
    [EWRAAddInput("data", "json", @"文档参数，格式如下：{
title:'文档标题',
desc:'文档说明',
author:'作者，默认为当前登录者',
key:'文档关键字',
category:'分类',
trade:'行业'
}", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAOutputDesc("返回结果", @"{
code:""success-成功，failed-失败"",
msg:""提示信息"",
doc_id:'生成的文档PK'
}")]
    object CreateDoc()
    {
        var data = PostDataD.data;
        if (data == null)
        {
            return new
            {
                code = "failed",
                msg = "缺少文档相关参数"
            };
        }
        string title = ComFunc.nvl(data.title);
        string desc = ComFunc.nvl(data.desc);
        string key = ComFunc.nvl(data.key);
        string category = ComFunc.nvl(data.category);
        string trade = ComFunc.nvl(data.trade);
        string author = ComFunc.nvl(data.author);
        if (author == "") author = ComFunc.nvl(TokenPayLoad["username"]);

        var metaup = DB.NewMetaUnitParameter();

        var default_columns = GetDefaultColumns().Select(d =>
        {
            var rtn = FrameDLRObject.CreateInstance();
            rtn.col_name = d.Name;
            rtn.col_desc = "";
            rtn.data_type = d.DataType;
            rtn.precision = d.Precision;
            rtn.scale = d.Scale;
            ((FrameDLRObject)rtn).SetValue("default", d.Default);
            rtn.is_allow_empty = d.AllowNull;
            rtn.is_pk = d.IsPK;
            rtn.format = "";
            rtn.memo = "";
            return rtn;
        }).ToList<object>();

        var db_type_list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "a")
                            select t).GetQueryList(metaup);
        var db_type = (from t in db_type_list
                       select new
                       {
                           data_type = t.DataType,
                           type_category = t.DataTypeCategory,
                           desc = t.DataTypeDesc,
                           is_allow_empty_zero_precision = BoolStd.ConvertTo(t.IsAllowEmptyOrZero_Precision, "True", "False"),
                           is_allow_empty_zero_scale = BoolStd.ConvertTo(t.IsAllowEmptyOrZero_Scale, "True", "False"),
                           is_auto_fix = BoolStd.ConvertTo(t.IsAutoFix, "True", "False"),
                           is_allow_pk = BoolStd.ConvertTo(t.IsAllowPK, "True", "False"),
                           ui_type = t.UI_TYPE,
                           db_type = t.Map_DBType,
                           db_type_default_precision = t.Map_DBType_DefaultPrecision,
                           db_type_default_scale = t.Map_DBType_DefaultScale
                       }).ToList();
        var metalist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                        join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_CATEGORY", "b").LeftJoin() on t.MetaCategoryNo equals t2.CategoryNo
                        select new
                        {
                            uid = t.MetaUID,
                            meta_name = t.MetaName,
                            meta_desc = t.MetaDesc,
                            category = t2.CategoryName,
                            ref_uid = t.MetaMainUID
                        }).GetQueryList(metaup);
        var columnlist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                          where t.IsVirsual == 0
                          select new
                          {
                              metauid = t.MetaUID,
                              col_name = t.MetaColumnName,
                              col_desc = t.MetaColumnDesc,
                              data_type = t.MetaDataType,
                              precision = t.MetaDataPrecision,
                              scale = t.MetaDataScale,
                              Default = t.MetaDataDefault,
                              is_allow_empty = t.MetaAllowEmpty,
                              is_pk = t.MetaIsPK,
                              format = t.MetaFormat,
                              memo = t.Memo
                          }).GetQueryList(metaup);
        var meta_list = (from t in metalist
                         select new
                         {
                             t.meta_name,
                             t.meta_desc,
                             t.category,
                             ref_main_meta = ComFunc.nvl(t.ref_uid) == "" ? "" : metalist.Where(w => w.uid == t.ref_uid).First().GetValue("meta_name"),
                             columns = columnlist.Where(w => w.metauid == t.uid).Select(d =>
                             {
                                 d.is_allow_empty = BoolStd.ConvertTo(d.is_allow_empty, "True", "False");
                                 d.is_pk = BoolStd.ConvertTo(d.is_pk, "True", "False");
                                 return d;
                             }).ToList()
                         }).ToList();


        var api = new FJKBAPI();
        var doc_id = "";
        var msg = "";
        if (api.CreateDoc("Meta Doc", title, "", author, desc, key, category, trade, new
        {
            meta_list,
            db_type,
            default_columns
        }, TokenPayLoad.ID, ComFunc.nvl(TokenPayLoad["username"]), ref msg, ref doc_id))
        {
            return new
            {
                code = "success",
                msg = "操作成功",
                doc_id
            };
        }
        else
        {
            return new
            {
                code = "failed",
                msg
            };
        }
    }

    private TableColumn[] GetDefaultColumns()
    {
        var rtn = new List<TableColumn>();
        rtn.AddRange(MetaDataUtilities.FixColumns.Select(d =>
        {
            var r = new TableColumn();
            r.Name = ComFunc.nvl(d.GetValue("column_name"));
            r.DataType = ComFunc.nvl(d.GetValue("db_type"));
            r.IsPK = BoolStd.IsNotBoolThen(d.GetValue("is_pk"));
            r.AllowNull = BoolStd.IsNotBoolThen(d.GetValue("is_allow_empty"));
            if (new string[] { "sort_no", "_status", "_active", "_lock" }.Contains(r.Name))
            {
                r.Default = "0";
            }
            if (new string[] { "varchar", "nvarchar" }.Contains(r.DataType))
            {
                r.Precision = IntStd.IsNotIntThen(d.GetValue("precision"));
            }

            return r;
        }).ToList());
        return rtn.ToArray();
    }
    public bool GenScriptBy(UnitParameter metaup, string id, ref string msg, ref dynamic rtn)
    {
        var metalist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                        where t.metauid == id
                        select t).GetQueryList(metaup);
        if (metalist.Count <= 0)
        {
            msg = "无该元数据";
            return false;
        }
        var metainfo = metalist.First();
        var metacolumnslist = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                               where t.MetaUID == id
                               select t).GetQueryList(metaup);
        if (rtn == null)
            rtn = FrameDLRObject.CreateInstance(EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);
        foreach (var key in metainfo.Keys)
        {
            if (metainfo.GetValue(key) is DateTime)
            {
                metainfo.SetValue(key, DateTimeStd.IsDateTimeThen(metainfo.GetValue(key), "yyyy-MM-dd HH:mm:ss"));
            }
        }
        rtn.MetaInfo = metainfo;
        rtn.MetaColumn = metacolumnslist.Select(d =>
        {
            var dobj = (FrameDLRObject)d;
            foreach (var key in dobj.Keys)
            {
                if (dobj.GetValue(key) is DateTime)
                {
                    dobj.SetValue(key, DateTimeStd.IsDateTimeThen(dobj.GetValue(key), "yyyy-MM-dd HH:mm:ss"));
                }
            }
            return d;
        });
        return true;
    }
    private bool DoCopyTable(UnitParameter metaup, UnitParameter up, string id, string to_table, bool with_data, ref string msg, ref string to_uid)
    {
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                where t.metauid == id
                select t;
        var list = s.GetQueryList(metaup);
        if (!s.IsExists(metaup))
        {
            msg = "元数据表不存在，不可进行操作";
            return false;
        }
        dynamic info = list.First();

        bool islocked = BoolStd.IsNotBoolThen(info.islocked, false);
        if (islocked)
        {
            msg = "元数据表已锁定，不可进行操作";
            return false;
        };
        bool iscreated = BoolStd.IsNotBoolThen(info.iscreated, false);
        if (!iscreated)
        {
            msg = "元数据表未创建，不可进行操作";
            return false;
        }
        if (!DB.IsTableExists(up, info.metaname))
        {
            msg = "元数据表不存在，不可进行操作";
            return false;
        }
        if (DB.IsTableExists(up, to_table))
        {
            msg = "目标表已存在，不可进行操作";
            return false;
        }

        var columns = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                       where t.MetaUID == info.MetaUID
                       select t).GetQueryList(metaup);
        var uid = Guid.NewGuid().ToString();
        dynamic new_table = ((FrameDLRObject)info).Clone();
        new_table.MetaName = to_table;
        new_table.MetaUID = uid;
        new_table.IsCreated = 1;
        new_table.IsLocked = 1;
        new_table.add_id = TokenPayLoad.ID;
        new_table.add_name = ComFunc.nvl(TokenPayLoad["username"]);
        new_table.add_ip = ClientInfo.IP;
        new_table.add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        new_table.last_id = TokenPayLoad.ID;
        new_table.last_name = ComFunc.nvl(TokenPayLoad["username"]);
        new_table.last_ip = ClientInfo.IP;
        new_table.last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        DB.QuickInsert(metaup, "EXTEND_METADATA", new_table);

        foreach (dynamic item in columns)
        {
            item.MetaUID = uid;
            item.add_id = TokenPayLoad.ID;
            item.add_name = ComFunc.nvl(TokenPayLoad["username"]);
            item.add_ip = ClientInfo.IP;
            item.add_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            item.last_id = TokenPayLoad.ID;
            item.last_name = ComFunc.nvl(TokenPayLoad["username"]);
            item.last_ip = ClientInfo.IP;
            item.last_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            DB.QuickInsert(metaup, "EXTEND_METADATA_COLUMNS", item);
        }

        UnitDataCollection r = DB.CopyTable(up, info.MetaName, to_table, with_data);
        if (ComFunc.nvl(r.ErrorMsg) != "")
        {
            msg = r.ErrorMsg;
            return false;
        }

        to_uid = uid;
        return true;
    }
    private bool DoDropTable(UnitParameter metaup, UnitParameter up, string ids, ref string msg)
    {
        var array = ids.Split(',').Where(p => ComFunc.nvl(p) != "");
        foreach (var id in array)
        {
            var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                    where t.metauid == id
                    select t;
            var list = s.GetQueryList(metaup);
            if (!s.IsExists(metaup))
            {
                return false;
            }
            dynamic info = list.First();

            bool islocked = BoolStd.IsNotBoolThen(info.islocked, false);
            if (islocked)
            {
                msg = "元数据表已锁定，不可进行操作";
                return false;
            }
            bool iscreated = BoolStd.IsNotBoolThen(info.iscreated, false);
            if (!iscreated)
            {
                msg = "元数据表未创建，不可进行操作";
                return false;
            }
            if (!DB.IsTableExists(up, info.metaname))
            {
                msg = "元数据表不存在，不可进行操作";
                return false;
            }
        }
        foreach (var id in array)
        {
            var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                    where t.metauid == id
                    select t;
            dynamic info = s.GetQueryList(metaup).First();
            //清空上传的文件目录
            var to_path = $"{upload_root_path}/meta_data/{info.metaname}/";
            if (Directory.Exists(to_path))
            {
                Directory.Delete(to_path, true);
            }

            UnitDataCollection r = DB.DropTable(up, info.metaname);
            if (ComFunc.nvl(r.ErrorMsg) != "")
            {
                msg = r.ErrorMsg;
                return false;
            }

            s.Update(metaup, new
            {
                iscreated = 0
            });
        }
        return true;
    }
    private bool DoCreateTable(UnitParameter metaup, UnitParameter up, string ids, ref string msg)
    {
        var array = ids.Split(',').Where(p => ComFunc.nvl(p) != "");
        foreach (var id in array)
        {
            var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                    where t.metauid == id
                    select t;
            var list = s.GetQueryList(metaup);
            if (!s.IsExists(metaup))
            {
                return false;
            }

            dynamic info = list.First();

            bool islocked = BoolStd.IsNotBoolThen(info.islocked, false);
            if (islocked)
            {
                msg = "元数据表已锁定，不可进行操作";
                return false;
            }
            bool iscreated = BoolStd.IsNotBoolThen(info.iscreated, false);
            if (iscreated)
            {
                msg = "元数据表已创建，不可进行操作";
                return false;
            }
            if (DB.IsTableExists(up, info.metaname))
            {
                msg = "元数据表已存在，不可进行操作";
                return false;
            }
        }
        foreach (var id in array)
        {
            var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                    where t.metauid == id
                    select t;
            dynamic info = s.GetQueryList(metaup).First();
            var columns = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                           join t2 in DB.LamdaTable(metaup, "EXTEND_METADATA_DATATYPE", "b") on t.MetaDataType equals t2.DataType
                           where t.metauid == id && t.IsVirsual == 0
                           select new
                           {
                               t.MetaUID,
                               t.MetaColumnName,
                               t.MetaDataType,
                               t.MetaDataPrecision,
                               t.MetaDataScale,
                               t.MetaDataDefault,
                               t.MetaAllowEmpty,
                               t.MetaIsPK,
                               t2.Map_DBType,
                               t2.Map_DBType_DefaultPrecision,
                               t2.Map_DBType_DefaultScale
                           }).GetQueryList(metaup);
            var schemas = columns.Select((p) =>
            {
                dynamic dobj = p;
                var rtn = new TableColumn();
                rtn.Name = dobj.MetaColumnName;
                rtn.DataType = dobj.Map_DBType;//Map_DBType才是实际数据类型，MetaDataType只是元数据类型
                var is_allow_empty_zero_precision = BoolStd.IsNotBoolThen(dobj.IsAllowEmptyOrZero_Precision);
                var is_allow_empty_zero_scale = BoolStd.IsNotBoolThen(dobj.IsAllowEmptyOrZero_Scale);
                var meta_precision = IntStd.IsNotIntThen(dobj.MetaDataPrecision);
                var meta_scale = IntStd.IsNotIntThen(dobj.MetaDataScale);
                var default_precision = IntStd.IsNotIntThen(dobj.Map_DBType_DefaultPrecision);
                var default_scale = IntStd.IsNotIntThen(dobj.Map_DBType_DefaultScale);
                //设定栏位的长度和精度
                if (meta_precision > 0)
                {
                    rtn.Precision = meta_precision;
                }
                else if (default_precision > 0)
                {
                    rtn.Precision = default_precision;
                }

                if (meta_scale > 0)
                {
                    rtn.Scale = meta_scale;
                }
                else if (default_scale > 0)
                {
                    rtn.Scale = default_scale;
                }

                rtn.Default = dobj.MetaDataDefault;
                rtn.AllowNull = BoolStd.IsNotBoolThen(dobj.MetaAllowEmpty, false);
                rtn.IsPK = BoolStd.IsNotBoolThen(dobj.MetaIsPK, false);
                return rtn;
            }).ToList();
            schemas.AddRange(GetDefaultColumns());
            UnitDataCollection r = DB.CreateTable(up, info.metaname, schemas.ToArray());
            if (ComFunc.nvl(r.ErrorMsg) != "")
            {
                msg = r.ErrorMsg;
                return false;
            }

            s.Update(metaup, new
            {
                islocked = 1,
                iscreated = 1
            });

        }
        return true;
    }
    private bool DoUnlock(UnitParameter metaup, string id, ref string msg)
    {
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                where t.metauid == id
                select t;
        var list = s.GetQueryList(metaup);
        if (!s.IsExists(metaup))
        {
            msg = "元数据表不存在";
            return false;
        }
        dynamic info = list.First();

        bool islocked = BoolStd.IsNotBoolThen(info.islocked, false);
        if (!islocked)
        {
            //msg = "元数据表已解锁，无需重复操作";
            //return false;
            return true;
        }
        s.Update(metaup, new
        {
            islocked = 0
        });

        return true;
    }
    private bool DoLock(UnitParameter metaup, string id, ref string msg)
    {
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                where t.metauid == id
                select t;
        var list = s.GetQueryList(metaup);
        if (!s.IsExists(metaup))
        {
            msg = "元数据表不存在";
            return false;
        }
        dynamic info = list.First();
        bool islocked = BoolStd.IsNotBoolThen(info.islocked, false);
        if (islocked)
        {
            //msg = "元数据表已锁定，无需重复操作";
            //return false;
            return true;
        }
        s.Update(metaup, new
        {
            islocked = 1
        });

        return true;
    }
    /// <summary>
    /// copy数据
    /// </summary>
    /// <param name="metaup"></param>
    /// <param name="id">原表uid</param>
    /// <param name="to_id">目标表uid</param>
    /// <param name="columns">json结构，先采用urlcode，再采用base64加密，json格式如下：{
    /// from_column1:'to_column1',//from_column1为来源表的栏位，to_column1为目标表的栏位
    /// ......
    /// from_columnN:'to_columnN'
    /// }</param
    /// <param name="where">array结构，先采用urlcode，再采用base64加密，array格式如下：[{
    /// column:'来源栏位名称',
    /// op:"操作符,like-模糊查询，=-精确查询，>-大于,>=-大于等于，-小于，<=-小于等于",
    /// value:'值'
    /// }]</param>
    /// <param name="if_not_exists"></param>
    /// <param name="msg"></param>
    /// <returns></returns>
    private bool DoCopyData(UnitParameter metaup, UnitParameter up, string id, string to_id, FrameDLRObject columns, object[] where, bool if_not_exists, ref string msg)
    {
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                where t.metauid == id
                select t;
        var list = s.GetQueryList(metaup);
        if (!s.IsExists(metaup))
        {
            msg = "元数据表不存在，不可进行操作";
            return false;
        }
        dynamic info = list.First();

        bool iscreated = BoolStd.IsNotBoolThen(info.iscreated, false);
        if (!iscreated)
        {
            msg = "元数据表未创建，不可进行操作";
            return false;
        }
        if (!DB.IsTableExists(up, info.metaname))
        {
            msg = "元数据表不存在，不可进行操作";
            return false;
        }
        var to_list = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                       where t.metauid == to_id
                       select t).GetQueryList(metaup);

        dynamic to_info = to_list.First();

        bool iscreated_to = BoolStd.IsNotBoolThen(to_info.iscreated, false);
        if (!iscreated_to)
        {
            msg = "目标表未创建，不可进行操作";
            return false;
        }
        if (!DB.IsTableExists(up, to_info.metaname))
        {
            msg = "目标表不存在，不可进行操作";
            return false;
        }
        var meta_columns = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                            where t.MetaUID == info.MetaUID && t.IsVirsual == 0
                            select new
                            {
                                column_name = t.MetaColumnName,
                                column_type = t.MetaDataType
                            }).GetQueryList(metaup);
        var to_meta_columns = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
                               where t.MetaUID == to_info.MetaUID && t.IsVirsual == 0
                               select new
                               {
                                   column_name = t.MetaColumnName,
                                   column_type = t.MetaDataType
                               }).GetQueryList(metaup);
        if (columns != null)
        {
            var meta_column_names = meta_columns.Select(d => ComFunc.nvl(d.GetValue("column_name")).ToLower()).ToList();
            var to_meta_column_names = to_meta_columns.Select(d => ComFunc.nvl(d.GetValue("column_name")).ToLower()).ToList();
            if (columns.Keys.Where(w => !meta_column_names.Contains(w.ToLower())).Count() > 0)
            {
                msg = "栏位设定与来源表设定不符";
                return false;
            }
            if (columns.Items.Select(d => ComFunc.nvl(d.Value)).Where(w => !to_meta_column_names.Contains(w.ToLower())).Count() > 0)
            {
                msg = "栏位设定与目标表设定不符";
                return false;
            }
        }
        foreach (var c in MetaDataUtilities.FixColumns)
        {
            var name = ComFunc.nvl(c.GetValue("column_name"));
            if (!columns.Keys.Contains(name))
            {
                columns.SetValue(name, c.GetValue("column_name"));
            }
        }

        var op_map = new Dictionary<string, string>();
        op_map.Add("like", "$like");
        op_map.Add("=", "$eq");
        op_map.Add(">", "$gt");
        op_map.Add(">=", "$gte");
        op_map.Add("<", "$lt");
        op_map.Add("<=", "$lte");

        FrameDLRObject whereobj = FrameDLRObject.CreateInstance();
        if (where != null)
        {
            foreach (dynamic item in where)
            {
                FrameDLRObject op = null;
                if (whereobj.Keys.Contains(item.column))
                {
                    op = whereobj.GetValue(item.column);
                }
                else
                {
                    op = FrameDLRObject.CreateInstance();
                    whereobj.SetValue(item.column, op);
                }
                op.SetValue(op_map[item.op], item.value);
            }
        }
        UnitDataCollection r = DB.CopyData(up, info.MetaName, to_info.MetaName, if_not_exists, columns, whereobj, true);
        if (ComFunc.nvl(r.ErrorMsg) != "")
        {
            msg = r.ErrorMsg;
            return false;
        }

        return true;
    }
    private bool DoDeleteMeta(UnitParameter metaup, UnitParameter up, string id, ref string msg)
    {
        var s = from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
                where t.metauid == id && t.islocked.isnull(0) == 0
                select t;
        var list = s.GetQueryList(metaup);
        if (!s.IsExists(metaup))
        {
            return false;
        }
        dynamic info = list.First();
        var iscreated = BoolStd.IsNotBoolThen(info.iscreated, false);

        s.Delete(metaup);

        //删除角色功能映射表
        (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
         where t.metauid == id
         select t).Delete(metaup);
        //drop相关的table
        if (iscreated && DB.IsTableExists(up, info.metaname))
        {
            var r = DB.DropTable(up, info.metaname);
            if (ComFunc.nvl(r.ErrorMsg) != "")
            {
                msg = r.ErrorMsg;
                return false;
            }
            //DB.DropTable(metaup, $"{info.metaname}_change_log");
        }

        return true;
    }

}
}
